Use base structs and embedding.
diff --git a/pagination.go b/pagination.go
index b0930e8..162db19 100644
--- a/pagination.go
+++ b/pagination.go
@@ -65,26 +65,61 @@
 
 // Page must be satisfied by the result type of any resource collection.
 // It allows clients to interact with the resource uniformly, regardless of whether or not or how it's paginated.
+// Generally, rather than implementing this interface directly, implementors should embed one of the concrete PageBase structs,
+// instead.
 type Page interface {
 
 	// NextPageURL generates the URL for the page of data that follows this collection.
 	// Return "" if no such page exists.
 	NextPageURL() (string, error)
+
+	// IsEmpty returns true if this Page has no items in it.
+	IsEmpty() (bool, error)
 }
 
-// SinglePage is a page that contains all of the results from an operation.
-type SinglePage LastHTTPResponse
+// MarkerPage is a stricter Page interface that describes additional functionality required for use with NewMarkerPager.
+// For convenience, embed the MarkedPageBase struct.
+type MarkerPage interface {
+	Page
+
+	// LastMark returns the last "marker" value on this page.
+	LastMark() (string, error)
+}
+
+// nullPage is an always-empty page that trivially satisfies all Page interfacts.
+// It's useful to be returned along with an error.
+type nullPage struct{}
 
 // NextPageURL always returns "" to indicate that there are no more pages to return.
-func (current SinglePage) NextPageURL() (string, error) {
+func (p nullPage) NextPageURL() (string, error) {
 	return "", nil
 }
 
-// LinkedPage is a page in a collection that provides navigational "Next" and "Previous" links within its result.
-type LinkedPage LastHTTPResponse
+// IsEmpty always returns true to prevent iteration over nullPages.
+func (p nullPage) IsEmpty() (bool, error) {
+	return true, nil
+}
+
+// LastMark always returns "" because the nullPage contains no items to have a mark.
+func (p nullPage) LastMark() (string, error) {
+	return "", nil
+}
+
+// SinglePageBase may be embedded in a Page that contains all of the results from an operation at once.
+type SinglePageBase LastHTTPResponse
+
+// NextPageURL always returns "" to indicate that there are no more pages to return.
+func (current SinglePageBase) NextPageURL() (string, error) {
+	return "", nil
+}
+
+// LinkedPageBase may be embedded to implement a page that provides navigational "Next" and "Previous" links within its result.
+type LinkedPageBase LastHTTPResponse
 
 // NextPageURL extracts the pagination structure from a JSON response and returns the "next" link, if one is present.
-func (current LinkedPage) NextPageURL() (string, error) {
+// It assumes that the links are available in a "links" element of the top-level response object.
+// If this is not the case, override NextPageURL on your result type.
+func (current LinkedPageBase) NextPageURL() (string, error) {
 	type response struct {
 		Links struct {
 			Next *string `mapstructure:"next,omitempty"`
@@ -104,19 +139,19 @@
 	return *r.Links.Next, nil
 }
 
-// MarkerPage is a page in a collection that's paginated by "limit" and "marker" query parameters.
-type MarkerPage struct {
+// MarkerPageBase is a page in a collection that's paginated by "limit" and "marker" query parameters.
+type MarkerPageBase struct {
 	LastHTTPResponse
 
-	// lastMark is a captured function that returns the final entry on a given page.
-	lastMark func(Page) (string, error)
+	// A reference to the embedding struct.
+	Self MarkerPage
 }
 
 // NextPageURL generates the URL for the page of results after this one.
-func (current MarkerPage) NextPageURL() (string, error) {
-	currentURL := current.LastHTTPResponse.URL
+func (current MarkerPageBase) NextPageURL() (string, error) {
+	currentURL := current.URL
 
-	mark, err := current.lastMark(current)
+	mark, err := current.Self.LastMark()
 	if err != nil {
 		return "", err
 	}
@@ -133,50 +168,46 @@
 	initialURL string
 
 	fetchNextPage func(string) (Page, error)
-
-	countPage func(Page) (int, error)
 }
 
 // NewPager constructs a manually-configured pager.
 // Supply the URL for the first page, a function that requests a specific page given a URL, and a function that counts a page.
-func NewPager(initialURL string, fetchNextPage func(string) (Page, error), countPage func(Page) (int, error)) Pager {
+func NewPager(initialURL string, fetchNextPage func(string) (Page, error)) Pager {
 	return Pager{
 		initialURL:    initialURL,
 		fetchNextPage: fetchNextPage,
-		countPage:     countPage,
 	}
 }
 
 // NewSinglePager constructs a Pager that "iterates" over a single Page.
-// Supply the URL to request.
-func NewSinglePager(client *ServiceClient, onlyURL string, countPage func(Page) (int, error)) Pager {
+// Supply the URL to request and a function that creates a Page of the appropriate type.
+func NewSinglePager(client *ServiceClient, onlyURL string, createPage func(resp LastHTTPResponse) Page) Pager {
 	consumed := false
 	single := func(_ string) (Page, error) {
 		if !consumed {
 			consumed = true
 			resp, err := request(client, onlyURL)
 			if err != nil {
-				return SinglePage{}, err
+				return nullPage{}, err
 			}
 
 			cp, err := RememberHTTPResponse(resp)
 			if err != nil {
-				return SinglePage{}, err
+				return nullPage{}, err
 			}
-			return SinglePage(cp), nil
+			return createPage(cp), nil
 		}
-		return SinglePage{}, ErrPageNotAvailable
+		return nullPage{}, ErrPageNotAvailable
 	}
 
 	return Pager{
 		initialURL:    "",
 		fetchNextPage: single,
-		countPage:     countPage,
 	}
 }
 
 // NewLinkedPager creates a Pager that uses a "links" element in the JSON response to locate the next page.
-func NewLinkedPager(client *ServiceClient, initialURL string, countPage func(Page) (int, error)) Pager {
+func NewLinkedPager(client *ServiceClient, initialURL string, createPage func(resp LastHTTPResponse) Page) Pager {
 	fetchNextPage := func(url string) (Page, error) {
 		resp, err := request(client, url)
 		if err != nil {
@@ -188,39 +219,36 @@
 			return nil, err
 		}
 
-		return LinkedPage(cp), nil
+		return createPage(cp), nil
 	}
 
 	return Pager{
 		initialURL:    initialURL,
 		fetchNextPage: fetchNextPage,
-		countPage:     countPage,
 	}
 }
 
 // NewMarkerPager creates a Pager that iterates over successive pages by issuing requests with a "marker" parameter set to the
 // final element of the previous Page.
-func NewMarkerPager(client *ServiceClient, initialURL string,
-	lastMark func(Page) (string, error), countPage func(Page) (int, error)) Pager {
+func NewMarkerPager(client *ServiceClient, initialURL string, createPage func(resp LastHTTPResponse) MarkerPage) Pager {
 
 	fetchNextPage := func(currentURL string) (Page, error) {
 		resp, err := request(client, currentURL)
 		if err != nil {
-			return nil, err
+			return nullPage{}, err
 		}
 
 		last, err := RememberHTTPResponse(resp)
 		if err != nil {
-			return nil, err
+			return nullPage{}, err
 		}
 
-		return MarkerPage{LastHTTPResponse: last, lastMark: lastMark}, nil
+		return createPage(last), nil
 	}
 
 	return Pager{
 		initialURL:    initialURL,
 		fetchNextPage: fetchNextPage,
-		countPage:     countPage,
 	}
 }
 
@@ -234,11 +262,11 @@
 			return err
 		}
 
-		count, err := p.countPage(currentPage)
+		empty, err := currentPage.IsEmpty()
 		if err != nil {
 			return err
 		}
-		if count == 0 {
+		if empty {
 			return nil
 		}
 
diff --git a/pagination_test.go b/pagination_test.go
index eb773bd..8ce36a2 100644
--- a/pagination_test.go
+++ b/pagination_test.go
@@ -20,12 +20,24 @@
 
 // SinglePage sample and test cases.
 
+type SinglePageResult struct {
+	SinglePageBase
+}
+
+func (r SinglePageResult) IsEmpty() (bool, error) {
+	is, err := ExtractSingleInts(r)
+	if err != nil {
+		return true, err
+	}
+	return len(is) == 0, nil
+}
+
 func ExtractSingleInts(page Page) ([]int, error) {
 	var response struct {
 		Ints []int `mapstructure:"ints"`
 	}
 
-	err := mapstructure.Decode(page.(SinglePage).Body, &response)
+	err := mapstructure.Decode(page.(SinglePageResult).Body, &response)
 	if err != nil {
 		return nil, err
 	}
@@ -42,15 +54,11 @@
 		fmt.Fprintf(w, `{ "ints": [1, 2, 3] }`)
 	})
 
-	countPage := func(p Page) (int, error) {
-		is, err := ExtractSingleInts(p)
-		if err != nil {
-			return 0, err
-		}
-		return len(is), nil
+	createPage := func(r LastHTTPResponse) Page {
+		return SinglePageResult{SinglePageBase(r)}
 	}
 
-	return NewSinglePager(client, testhelper.Server.URL+"/only", countPage)
+	return NewSinglePager(client, testhelper.Server.URL+"/only", createPage)
 }
 
 func TestEnumerateSinglePaged(t *testing.T) {
@@ -63,31 +71,34 @@
 
 		expected := []int{1, 2, 3}
 		actual, err := ExtractSingleInts(page)
-		if err != nil {
-			return false, err
-		}
-		if !reflect.DeepEqual(expected, actual) {
-			t.Errorf("Expected %v, but was %v", expected, actual)
-		}
+		testhelper.AssertNoErr(t, err)
+		testhelper.CheckDeepEquals(t, expected, actual)
 		return true, nil
 	})
-	if err != nil {
-		t.Fatalf("Unexpected error calling EachPage: %v", err)
-	}
-
-	if callCount != 1 {
-		t.Errorf("Callback was invoked %d times", callCount)
-	}
+	testhelper.CheckNoErr(t, err)
+	testhelper.CheckEquals(t, 1, callCount)
 }
 
 // LinkedPager sample and test cases.
 
+type LinkedPageResult struct {
+	LinkedPageBase
+}
+
+func (r LinkedPageResult) IsEmpty() (bool, error) {
+	is, err := ExtractLinkedInts(r)
+	if err != nil {
+		return true, nil
+	}
+	return len(is) == 0, nil
+}
+
 func ExtractLinkedInts(page Page) ([]int, error) {
 	var response struct {
 		Ints []int `mapstructure:"ints"`
 	}
 
-	err := mapstructure.Decode(page.(LinkedPage).Body, &response)
+	err := mapstructure.Decode(page.(LinkedPageResult).Body, &response)
 	if err != nil {
 		return nil, err
 	}
@@ -115,15 +126,11 @@
 
 	client := createClient()
 
-	countPage := func(p Page) (int, error) {
-		is, err := ExtractLinkedInts(p)
-		if err != nil {
-			return 0, err
-		}
-		return len(is), nil
+	createPage := func(r LastHTTPResponse) Page {
+		return LinkedPageResult{LinkedPageBase(r)}
 	}
 
-	return NewLinkedPager(client, testhelper.Server.URL+"/page1", countPage)
+	return NewLinkedPager(client, testhelper.Server.URL+"/page1", createPage)
 }
 
 func TestEnumerateLinked(t *testing.T) {
@@ -168,6 +175,31 @@
 	}
 }
 
+// MarkerPager sample and test cases.
+
+type MarkerPageResult struct {
+	MarkerPageBase
+}
+
+func (r MarkerPageResult) IsEmpty() (bool, error) {
+	results, err := ExtractMarkerStrings(r)
+	if err != nil {
+		return true, err
+	}
+	return len(results) == 0, err
+}
+
+func (r MarkerPageResult) LastMark() (string, error) {
+	results, err := ExtractMarkerStrings(r)
+	if err != nil {
+		return "", err
+	}
+	if len(results) == 0 {
+		return "", nil
+	}
+	return results[len(results)-1], nil
+}
+
 func createMarkerPaged(t *testing.T) Pager {
 	testhelper.SetupHTTP()
 
@@ -190,28 +222,17 @@
 
 	client := createClient()
 
-	lastMark := func(p Page) (string, error) {
-		items, err := ExtractMarkerStrings(p)
-		if err != nil {
-			return "", err
-		}
-		return items[len(items)-1], nil
+	createPage := func(r LastHTTPResponse) MarkerPage {
+		p := MarkerPageResult{MarkerPageBase{LastHTTPResponse: r}}
+		p.MarkerPageBase.Self = p
+		return p
 	}
 
-	countPage := func(p Page) (int, error) {
-		items, err := ExtractMarkerStrings(p)
-		if err != nil {
-			return 0, err
-		}
-		fmt.Printf("Counting items [%#v] = [%d]\n", items, len(items))
-		return len(items), nil
-	}
-
-	return NewMarkerPager(client, testhelper.Server.URL+"/page", lastMark, countPage)
+	return NewMarkerPager(client, testhelper.Server.URL+"/page", createPage)
 }
 
 func ExtractMarkerStrings(page Page) ([]string, error) {
-	content := page.(MarkerPage).Body.([]uint8)
+	content := page.(MarkerPageResult).Body.([]uint8)
 	parts := strings.Split(string(content), "\n")
 	results := make([]string, 0, len(parts))
 	for _, part := range parts {