diff --git a/CHANGELOG.txt b/CHANGELOG.txt
index 073ad4cebde1a1bbdcc2109936c8235278705f04..1e07b109539ddf0df724b0c1ec4cf0008cf910c7 100644
--- a/CHANGELOG.txt
+++ b/CHANGELOG.txt
@@ -3,6 +3,8 @@
 Feeds 7.x 2.0 XXXXXXXXXXXXXXXXXXX
 ---------------------------------
 
+- #928728: Track source states by stage, not by plugin. Note: call signature of
+  FeedsSource::state() has changed.
 - #923318: Fix Fatal error: Call to a member function import() on a non-object
   occuring on cron.
 - Clean up basic settings form.
diff --git a/includes/FeedsSource.inc b/includes/FeedsSource.inc
index f044d1469ee008a0f193e363a0d83e98b226a069..989d942110a3e7e73483cdc12322114d760fb8f3 100644
--- a/includes/FeedsSource.inc
+++ b/includes/FeedsSource.inc
@@ -6,6 +6,14 @@
  * Definition of FeedsSourceInterface and FeedsSource class.
  */
 
+/**
+ * Denote a import or clearing stage. Used for multi page processing.
+ */
+define('FEEDS_FETCH', 'fetch');
+define('FEEDS_PARSE', 'parse');
+define('FEEDS_PROCESS', 'process');
+define('FEEDS_PROCESS_CLEAR', 'process_clear');
+
 /**
  * Declares an interface for a class that defines default values and form
  * descriptions for a FeedSource.
@@ -198,7 +206,7 @@ class FeedsSource extends FeedsConfigurable {
       if (empty($this->fetcher_result) || FEEDS_BATCH_COMPLETE == $this->progressParsing()) {
         $this->fetcher_result = $this->importer->fetcher->fetch($this);
         // Clean the parser's state, we are parsing an entirely new file.
-        unset($this->state[get_class($this->importer->parser)]);
+        unset($this->state[FEEDS_PARSE]);
       }
 
       // Parse.
@@ -260,15 +268,15 @@ class FeedsSource extends FeedsConfigurable {
    * Report progress as float between 0 and 1. 1 = FEEDS_BATCH_COMPLETE.
    */
   public function progressParsing() {
-    return $this->state($this->importer->parser)->progress();
+    return $this->state(FEEDS_PARSE)->progress();
   }
 
   /**
    * Report progress as float between 0 and 1. 1 = FEEDS_BATCH_COMPLETE.
    */
   public function progressImporting() {
-    $fetcher = $this->state($this->importer->fetcher);
-    $parser = $this->state($this->importer->parser);
+    $fetcher = $this->state(FEEDS_FETCH);
+    $parser = $this->state(FEEDS_PARSE);
     if ($fetcher->progress() == FEEDS_BATCH_COMPLETE && $parser->progress() == FEEDS_BATCH_COMPLETE) {
       return FEEDS_BATCH_COMPLETE;
     }
@@ -281,30 +289,28 @@ class FeedsSource extends FeedsConfigurable {
    * Report progress on clearing.
    */
   public function progressClearing() {
-    return $this->state($this->importer->processor)->progress();
+    return $this->state(FEEDS_PROCESS_CLEAR)->progress();
   }
 
   /**
-   * Return a state object for a given object. Lazy instantiates new states.
+   * Return a state object for a given stage. Lazy instantiates new states.
    *
    * @todo Rename getConfigFor() accordingly to config().
    *
-   * @param FeedsSourceInterface $client
-   *   An object that implements the FeedsSourceInterface, usually a fetcher,
-   *   parser or processor plugin.
+   * @param $stage
+   *   One of FEEDS_FETCH, FEEDS_PARSE, FEEDS_PROCESS or FEEDS_PROCESS_CLEAR.
    *
    * @return
-   *   The FeedsState object for the given client.
+   *   The FeedsState object for the given stage.
    */
-  public function state(FeedsSourceInterface $client) {
-    $class = get_class($client);
+  public function state($stage) {
     if (!is_array($this->state)) {
       $this->state = array();
     }
-    if (!isset($this->state[$class])) {
-      $this->state[$class] = new FeedsState();
+    if (!isset($this->state[$stage])) {
+      $this->state[$stage] = new FeedsState();
     }
-    return $this->state[$class];
+    return $this->state[$stage];
   }
 
   /**
diff --git a/plugins/FeedsCSVParser.inc b/plugins/FeedsCSVParser.inc
index 5762bad4697c8f2551228ba06213371496e5a518..3cbd322c18fee3c20b7dd1c484ec8bd6cffbcd2e 100644
--- a/plugins/FeedsCSVParser.inc
+++ b/plugins/FeedsCSVParser.inc
@@ -11,7 +11,7 @@ class FeedsCSVParser extends FeedsParser {
    */
   public function parse(FeedsSource $source, FeedsFetcherResult $fetcher_result) {
     $source_config = $source->getConfigFor($this);
-    $state = $source->state($this);
+    $state = $source->state(FEEDS_PARSE);
 
     // Load and configure parser.
     feeds_include_library('ParserCSV.inc', 'ParserCSV');
diff --git a/plugins/FeedsFeedNodeProcessor.inc b/plugins/FeedsFeedNodeProcessor.inc
index d7f9a8d0ff443fe8984f2e746976b670616c2a4d..00926e748062855d1a0820962d2ea88a30fdeddf 100644
--- a/plugins/FeedsFeedNodeProcessor.inc
+++ b/plugins/FeedsFeedNodeProcessor.inc
@@ -16,7 +16,7 @@ class FeedsFeedNodeProcessor extends FeedsProcessor {
    * Implements FeedsProcessor::process().
    */
   public function process(FeedsSource $source, FeedsParserResult $parser_result) {
-    $state = $source->state($this);
+    $state = $source->state(FEEDS_PROCESS);
     while ($item = $parser_result->shiftItem()) {
 
       // If the target item does not exist OR if update_existing is enabled,
diff --git a/plugins/FeedsFileFetcher.inc b/plugins/FeedsFileFetcher.inc
index 3829b28cde8a1a20a4871eba149608f03f73947c..22ef9cb838fed5d3e0e4c60930fd6b3ee3454fbe 100644
--- a/plugins/FeedsFileFetcher.inc
+++ b/plugins/FeedsFileFetcher.inc
@@ -54,7 +54,7 @@ class FeedsFileFetcher extends FeedsFetcher {
     }
 
     // Batch if this is a directory.
-    $state = $source->state($this);
+    $state = $source->state(FEEDS_FETCH);
     $files = array();
     if (!isset($state->files)) {
       $state->files = $this->listFiles($source_config['source']);
diff --git a/plugins/FeedsNodeProcessor.inc b/plugins/FeedsNodeProcessor.inc
index 75bb2f65d5420f360159b2fd6ec305bf68bf25bb..6e6c83854c59439233f538ded5f04230d1cad683 100644
--- a/plugins/FeedsNodeProcessor.inc
+++ b/plugins/FeedsNodeProcessor.inc
@@ -23,7 +23,7 @@ class FeedsNodeProcessor extends FeedsProcessor {
    * Implements FeedsProcessor::process().
    */
   public function process(FeedsSource $source, FeedsParserResult $parser_result) {
-    $state = $source->state($this);
+    $state = $source->state(FEEDS_PROCESS);
 
     while ($item = $parser_result->shiftItem()) {
       if (!($nid = $this->existingItemId($source, $parser_result)) ||
@@ -74,7 +74,7 @@ class FeedsNodeProcessor extends FeedsProcessor {
    * Implements FeedsProcessor::clear().
    */
   public function clear(FeedsSource $source) {
-    $state = $source->state($this);
+    $state = $source->state(FEEDS_PROCESS_CLEAR);
     if (empty($state->total)) {
       $state->total = db_query("SELECT COUNT(n.nid) FROM {node} n JOIN {feeds_node_item} fn ON n.nid = fn.nid WHERE fn.id = :id AND fn.feed_nid = :nid", array(':id' => $source->id, ':nid' => $source->feed_nid))->fetchField();
     }