diff --git a/core/modules/migrate/lib/Drupal/migrate/Annotation/MigrateDestination.php b/core/modules/migrate/lib/Drupal/migrate/Annotation/MigrateDestination.php
new file mode 100644
index 0000000..bfeff62
--- /dev/null
+++ b/core/modules/migrate/lib/Drupal/migrate/Annotation/MigrateDestination.php
@@ -0,0 +1,46 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\migrate\Annotation\MigrateDestination.
+ */
+
+namespace Drupal\migrate\Annotation;
+
+use Drupal\Component\Annotation\Plugin;
+
+/**
+ * Defines a migration destination plugin annotation object.
+ *
+ * @Annotation
+ */
+class MigrateDestination extends Plugin {
+
+  /**
+   * A unique identifier for the process plugin.
+   *
+   * @var string
+   */
+  public $id;
+
+  /**
+   * Whether requirements are met.
+   *
+   * If TRUE and a 'provider' key is present in the annotation then the
+   * default destination plugin manager will set this to FALSE if the
+   * provider (module/theme) doesn't exist.
+   *
+   * @var bool
+   */
+  public $requirements_met = TRUE;
+
+  /**
+   * A class to make the plugin derivative aware.
+   *
+   * @var string
+   *
+   * @see \Drupal\Component\Plugin\Discovery\DerivativeDiscoveryDecorator
+   */
+  public $derivative;
+
+}
diff --git a/core/modules/migrate/lib/Drupal/migrate/Annotation/MigrateSource.php b/core/modules/migrate/lib/Drupal/migrate/Annotation/MigrateSource.php
new file mode 100644
index 0000000..86dd857
--- /dev/null
+++ b/core/modules/migrate/lib/Drupal/migrate/Annotation/MigrateSource.php
@@ -0,0 +1,33 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\migrate\Annotation\MigrateDestination.
+ */
+
+namespace Drupal\migrate\Annotation;
+
+use Drupal\Component\Annotation\Plugin;
+
+/**
+ * Defines a migration destination plugin annotation object.
+ *
+ * @Annotation
+ */
+class MigrateSource extends Plugin {
+
+  /**
+   * A unique identifier for the process plugin.
+   *
+   * @var string
+   */
+  public $id;
+
+  /**
+   * Whether requirements are met.
+   *
+   * @var bool
+   */
+  public $requirements_met = TRUE;
+
+}
diff --git a/core/modules/migrate/lib/Drupal/migrate/Entity/Migration.php b/core/modules/migrate/lib/Drupal/migrate/Entity/Migration.php
index 3967aec..75c2cc6 100644
--- a/core/modules/migrate/lib/Drupal/migrate/Entity/Migration.php
+++ b/core/modules/migrate/lib/Drupal/migrate/Entity/Migration.php
@@ -10,6 +10,7 @@
 use Drupal\Core\Config\Entity\ConfigEntityBase;
 use Drupal\migrate\MigrateException;
 use Drupal\migrate\Plugin\MigrateIdMapInterface;
+use Drupal\migrate\Plugin\RequirementsInterface;
 
 /**
  * Defines the Migration entity.
@@ -22,12 +23,7 @@
  *   label = @Translation("Migration"),
  *   module = "migrate",
  *   controllers = {
- *     "list" = "Drupal\Core\Config\Entity\DraggableListController",
- *     "form" = {
- *       "add" = "Drupal\Core\Entity\EntityFormController",
- *       "edit" = "Drupal\Core\Entity\EntityFormController",
- *       "delete" = "Drupal\Core\Entity\EntityFormController"
- *     }
+ *     "storage" = "Drupal\migrate\MigrationStorageController"
  *   },
  *   entity_keys = {
  *     "id" = "id",
@@ -36,7 +32,7 @@
  *   }
  * )
  */
-class Migration extends ConfigEntityBase implements MigrationInterface {
+class Migration extends ConfigEntityBase implements MigrationInterface, RequirementsInterface {
 
   /**
    * The migration ID (machine name).
@@ -141,7 +137,7 @@ class Migration extends ConfigEntityBase implements MigrationInterface {
    *
    * @var array
    */
-  public $destinationIds = array();
+  public $destinationIds = FALSE;
 
   /**
    * Information on the highwater mark.
@@ -171,16 +167,6 @@ class Migration extends ConfigEntityBase implements MigrationInterface {
   public $sourceRowStatus = MigrateIdMapInterface::STATUS_IMPORTED;
 
   /**
-   * The ratio of the memory limit at which an operation will be interrupted.
-   *
-   * Can be overridden by a Migration subclass if one would like to push the
-   * envelope. Defaults to 0.85.
-   *
-   * @var float
-   */
-  protected $memoryThreshold = 0.85;
-
-  /**
    * @var \Drupal\Core\KeyValueStore\KeyValueStoreInterface
    */
   protected $highwaterStorage;
@@ -191,21 +177,18 @@ class Migration extends ConfigEntityBase implements MigrationInterface {
   public $trackLastImported = FALSE;
 
   /**
-   * The ratio of the time limit at which an operation will be interrupted.
-   *
-   * Can be overridden by a Migration subclass if one would like to push the
-   * envelope. Defaults to 0.9.
-   *
-   * @var float
-   */
-  public $timeThreshold = 0.90;
-
-  /**
-   * The time limit when executing the migration.
+   * These migrations must be already executed before this migration can run.
    *
    * @var array
    */
-  public $limit = array();
+  protected $requirements = array();
+
+  /**
+   * These migrations, if ran at all, must be executed before this migration.
+   *
+   *@var array
+   */
+  public $dependencies = array();
 
   /**
    * {@inheritdoc}
@@ -301,11 +284,56 @@ protected function getHighWaterStorage() {
     return $this->highwaterStorage;
   }
 
+  /**
+   * {@inheritdoc}
+   */
   public function getHighwater() {
     return $this->getHighWaterStorage()->get($this->id());
   }
 
+  /**
+   * {@inheritdoc}
+   */
   public function saveHighwater($highwater) {
     $this->getHighWaterStorage()->set($this->id(), $highwater);
   }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function checkRequirements() {
+    // Check whether the current migration source and destination plugin
+    // requirements are met or not.
+    try {
+      if ($this->getSourcePlugin() instanceof RequirementsInterface && !$this->getSourcePlugin()->checkRequirements()) {
+        return FALSE;
+      }
+      if ($this->getDestinationPlugin() instanceof RequirementsInterface && !$this->getDestinationPlugin()->checkRequirements()) {
+        return FALSE;
+      }
+
+      /** @var \Drupal\migrate\Entity\MigrationInterface[] $required_migrations */
+      $required_migrations = entity_load_multiple('migration', $this->requirements);
+      // Check if the dependencies are in good shape.
+      foreach ($required_migrations as $required_migration) {
+        // If the dependent source migration has no IDs then no mappings can
+        // be recorded thus it is impossible to see whether the migration ran.
+        if (!$required_migration->getSourcePlugin()->getIds()) {
+          return FALSE;
+        }
+
+        // If the dependent migration has not processed any record, it means the
+        // dependency requirements are not met.
+        if (!$required_migration->getIdMap()->processedCount()) {
+          return FALSE;
+        }
+      }
+    }
+    catch (\Exception $e) {
+      return FALSE;
+    }
+
+    return TRUE;
+  }
+
 }
diff --git a/core/modules/migrate/lib/Drupal/migrate/Entity/MigrationInterface.php b/core/modules/migrate/lib/Drupal/migrate/Entity/MigrationInterface.php
index 4999cdf..732291f 100644
--- a/core/modules/migrate/lib/Drupal/migrate/Entity/MigrationInterface.php
+++ b/core/modules/migrate/lib/Drupal/migrate/Entity/MigrationInterface.php
@@ -84,10 +84,17 @@ public function getDestinationPlugin();
   public function getIdMap();
 
   /**
+   * The current value of the highwater mark.
+   *
    * @return int
    */
   public function getHighwater();
 
+  /**
+   * Save the highwater mark.
+   *
+   * @return int
+   */
   public function saveHighwater($highwater);
 
 }
diff --git a/core/modules/migrate/lib/Drupal/migrate/MigrateBuildDependencyInterface.php b/core/modules/migrate/lib/Drupal/migrate/MigrateBuildDependencyInterface.php
new file mode 100644
index 0000000..e06c95c
--- /dev/null
+++ b/core/modules/migrate/lib/Drupal/migrate/MigrateBuildDependencyInterface.php
@@ -0,0 +1,24 @@
+<?php
+/**
+ * @file
+ * Contains \Drupal\migrate\MigrateBuildDependencyInterface.
+ */
+
+namespace Drupal\migrate;
+
+
+interface MigrateBuildDependencyInterface {
+
+  /**
+   * Builds a dependency tree for the migrations and set their order.
+   *
+   * @param \Drupal\migrate\Entity\MigrationInterface[] $migrations
+   *   Array of loaded migrations with their declared dependencies.
+   * @param array $dynamic_ids
+   *   Keys are dynamic ids (for example node:*) values are a list of loaded
+   *   migration ids (for example node:page, node:article).
+   *
+   * @return array
+   */
+  public function buildDependencyMigration(array $migrations, array $dynamic_ids);
+}
diff --git a/core/modules/migrate/lib/Drupal/migrate/MigrateException.php b/core/modules/migrate/lib/Drupal/migrate/MigrateException.php
index d07c04f..48334bf 100644
--- a/core/modules/migrate/lib/Drupal/migrate/MigrateException.php
+++ b/core/modules/migrate/lib/Drupal/migrate/MigrateException.php
@@ -48,7 +48,7 @@ class MigrateException extends \Exception {
    *   The status of the item for the map table, a MigrateMap::STATUS_*
    *   constant.
    */
-  public function __construct($message = null, $code = 0, \Exception $previous = null, $level = MigrationInterface::MESSAGE_ERROR, $status = MigrateIdMapInterface::STATUS_FAILED) {
+  public function __construct($message = NULL, $code = 0, \Exception $previous = NULL, $level = MigrationInterface::MESSAGE_ERROR, $status = MigrateIdMapInterface::STATUS_FAILED) {
     $this->level = $level;
     $this->status = $status;
     parent::__construct($message);
@@ -58,6 +58,7 @@ public function __construct($message = null, $code = 0, \Exception $previous = n
    * Gets the level.
    *
    * @return int
+   *   An integer status code. @see Migration::MESSAGE_*
    */
   public function getLevel() {
     return $this->level;
@@ -67,6 +68,7 @@ public function getLevel() {
    * Gets the status of the current item.
    *
    * @return int
+   *   An integer status code. @see MigrateMap::STATUS_*
    */
   public function getStatus() {
     return $this->status;
diff --git a/core/modules/migrate/lib/Drupal/migrate/MigrateExecutable.php b/core/modules/migrate/lib/Drupal/migrate/MigrateExecutable.php
index 104f187..73974d7 100644
--- a/core/modules/migrate/lib/Drupal/migrate/MigrateExecutable.php
+++ b/core/modules/migrate/lib/Drupal/migrate/MigrateExecutable.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\migrate;
 
+use Drupal\Component\Utility\String;
 use Drupal\Core\Utility\Error;
 use Drupal\migrate\Entity\MigrationInterface;
 use Drupal\migrate\Plugin\MigrateIdMapInterface;
@@ -85,6 +86,33 @@ class MigrateExecutable {
   protected $maxExecTime;
 
   /**
+   * The ratio of the memory limit at which an operation will be interrupted.
+   *
+   * Can be overridden by a Migration subclass if one would like to push the
+   * envelope. Defaults to 0.85.
+   *
+   * @var float
+   */
+  protected $memoryThreshold = 0.85;
+
+  /**
+   * The ratio of the time limit at which an operation will be interrupted.
+   *
+   * Can be overridden by a Migration subclass if one would like to push the
+   * envelope. Defaults to 0.9.
+   *
+   * @var float
+   */
+  public $timeThreshold = 0.90;
+
+  /**
+   * The time limit when executing the migration.
+   *
+   * @var array
+   */
+  public $limit = array();
+
+  /**
    * The configuration values of the source.
    *
    * @var array
@@ -216,9 +244,14 @@ public function getSource() {
    * Performs an import operation - migrate items from source to destination.
    */
   public function import() {
+    // Knock off migration if the requirements haven't been met.
+    if (!$this->migration->checkRequirements()) {
+      $this->message->display(
+        $this->t('Migration @id did not meet the requirements', array('@id' => $this->migration->id())), 'error');
+      return MigrationInterface::RESULT_FAILED;
+    }
     $return = MigrationInterface::RESULT_COMPLETED;
     $source = $this->getSource();
-    $destination = $this->migration->getDestinationPlugin();
     $id_map = $this->migration->getIdMap();
 
     try {
@@ -227,10 +260,12 @@ public function import() {
     catch (\Exception $e) {
       $this->message->display(
         $this->t('Migration failed with source plugin exception: !e',
-          array('!e' => $e->getMessage())));
+          array('!e' => $e->getMessage())), 'error');
       return MigrationInterface::RESULT_FAILED;
     }
 
+    $destination = $this->migration->getDestinationPlugin();
+
     while ($source->valid()) {
       $row = $source->current();
       if ($this->sourceIdValues = $row->getSourceIdValues()) {
@@ -250,11 +285,12 @@ public function import() {
 
       if ($save) {
         try {
-          $destination_id_values = $destination->import($row);
-          // @todo Handle the successful but no ID case like config,
-          //   https://drupal.org/node/2160835.
+          $destination_id_values = $destination->import($row, $id_map->lookupDestinationId($this->sourceIdValues));
           if ($destination_id_values) {
-            $id_map->saveIdMapping($row, $destination_id_values, $this->sourceRowStatus, $this->rollbackAction);
+            // We do not save an idMap entry for config.
+            if ($destination_id_values !== TRUE) {
+              $id_map->saveIdMapping($row, $destination_id_values, $this->sourceRowStatus, $this->rollbackAction);
+            }
             $this->successesSinceFeedback++;
             $this->totalSuccesses++;
           }
@@ -270,7 +306,7 @@ public function import() {
         catch (MigrateException $e) {
           $this->migration->getIdMap()->saveIdMapping($row, array(), $e->getStatus(), $this->rollbackAction);
           $this->saveMessage($e->getMessage(), $e->getLevel());
-          $this->message->display($e->getMessage());
+          $this->message->display($e->getMessage(), 'error');
         }
         catch (\Exception $e) {
           $this->migration->getIdMap()->saveIdMapping($row, array(), MigrateIdMapInterface::STATUS_FAILED, $this->rollbackAction);
@@ -299,7 +335,7 @@ public function import() {
       catch (\Exception $e) {
         $this->message->display(
           $this->t('Migration failed with source plugin exception: !e',
-            array('!e' => $e->getMessage())));
+            array('!e' => $e->getMessage())), 'error');
         return MigrationInterface::RESULT_FAILED;
       }
     }
@@ -345,13 +381,27 @@ public function processRow(Row $row, array $process = NULL, $value = NULL) {
           if (!is_array($value)) {
             throw new MigrateException(sprintf('Pipeline failed for destination %s: %s got instead of an array,', $destination, $value));
           }
+          $break = FALSE;
           foreach ($value as $scalar_value) {
-            $new_value[] = $plugin->transform($scalar_value, $this, $row, $destination);
+            try {
+              $new_value[] = $plugin->transform($scalar_value, $this, $row, $destination);
+            }
+            catch (MigrateSkipProcessException $e) {
+              $break = TRUE;
+            }
           }
           $value = $new_value;
+          if ($break) {
+            break;
+          }
         }
         else {
-          $value = $plugin->transform($value, $this, $row, $destination);
+          try {
+            $value = $plugin->transform($value, $this, $row, $destination);
+          }
+          catch (MigrateSkipProcessException $e) {
+            break;
+          }
           $multiple = $multiple || $plugin->multiple();
         }
       }
@@ -402,7 +452,7 @@ protected function timeOptionExceeded() {
    *   The time limit, NULL if no limit or if the units were not in seconds.
    */
   public function getTimeLimit() {
-    $limit = $this->migration->get('limit');
+    $limit = $this->limit;
     if (isset($limit['unit']) && isset($limit['value']) && ($limit['unit'] == 'seconds' || $limit['unit'] == 'second')) {
       return $limit['value'];
     }
@@ -488,7 +538,7 @@ protected function checkStatus() {
   protected function memoryExceeded() {
     $usage = $this->getMemoryUsage();
     $pct_memory = $usage / $this->memoryLimit;
-    if (!$threshold = $this->migration->get('memoryThreshold')) {
+    if (!$threshold = $this->memoryThreshold) {
       return FALSE;
     }
     if ($pct_memory > $threshold) {
@@ -570,7 +620,7 @@ protected function formatSize($size) {
    *   TRUE if the threshold is exceeded, FALSE if not.
    */
   protected function maxExecTimeExceeded() {
-    return $this->maxExecTime && (($this->getTimeElapsed() / $this->maxExecTime) > $this->migration->get('timeThreshold'));
+    return $this->maxExecTime && (($this->getTimeElapsed() / $this->maxExecTime) > $this->timeThreshold);
   }
 
   /**
@@ -599,7 +649,7 @@ public function handleException(\Exception $exception, $save = TRUE) {
     if ($save) {
       $this->saveMessage($message);
     }
-    $this->message->display($message);
+    $this->message->display($message, 'error');
   }
 
   /**
diff --git a/core/modules/migrate/lib/Drupal/migrate/MigrateMessage.php b/core/modules/migrate/lib/Drupal/migrate/MigrateMessage.php
index d90297e..a9c8916 100644
--- a/core/modules/migrate/lib/Drupal/migrate/MigrateMessage.php
+++ b/core/modules/migrate/lib/Drupal/migrate/MigrateMessage.php
@@ -13,15 +13,20 @@
 class MigrateMessage implements MigrateMessageInterface {
 
   /**
-   * Displays a migrate message.
+   * The map between migrate status and watchdog severity.
    *
-   * @param string $message
-   *   The message to display.
-   * @param string $type
-   *   The type of message, for example: status or warning.
+   * @var array
    */
-  function display($message, $type = 'status') {
-    drupal_set_message($message, $type);
+  protected $map = array(
+    'status' => WATCHDOG_INFO,
+    'error' => WATCHDOG_ERROR,
+  );
+
+  /**
+   * {@inheritdoc}
+   */
+  public function display($message, $type = 'status') {
+    watchdog('migrate', $message, array(), isset($this->map[$type]) ? $this->map[$type] : WATCHDOG_NOTICE);
   }
 
 }
diff --git a/core/modules/migrate/lib/Drupal/migrate/MigrateMessageInterface.php b/core/modules/migrate/lib/Drupal/migrate/MigrateMessageInterface.php
index bcf3753..42d6e95 100644
--- a/core/modules/migrate/lib/Drupal/migrate/MigrateMessageInterface.php
+++ b/core/modules/migrate/lib/Drupal/migrate/MigrateMessageInterface.php
@@ -10,10 +10,12 @@
 interface MigrateMessageInterface {
 
   /**
-   * @param $message
-   * @param string $type
+   * Displays a migrate message.
    *
-   * @return mixed
+   * @param string $message
+   *   The message to display.
+   * @param string $type
+   *   The type of message, for example: status or warning.
    */
-  function display($message, $type = 'status');
+  public function display($message, $type = 'status');
 }
diff --git a/core/modules/migrate/lib/Drupal/migrate/MigratePassword.php b/core/modules/migrate/lib/Drupal/migrate/MigratePassword.php
new file mode 100644
index 0000000..fc8ed1c
--- /dev/null
+++ b/core/modules/migrate/lib/Drupal/migrate/MigratePassword.php
@@ -0,0 +1,84 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\migrate\MigratePassword.
+ */
+
+namespace Drupal\migrate;
+
+use Drupal\Core\Password\PasswordInterface;
+use Drupal\user\UserInterface;
+
+/**
+ * Replaces the original 'password' service in order to prefix the MD5 re-hashed
+ * passwords with the 'U' flag. The new salted hash is recreated on first login
+ * similarly to the D6->D7 upgrade path.
+ */
+class MigratePassword implements PasswordInterface {
+
+  /**
+   * The original password service.
+   *
+   * @var \Drupal\Core\Password\PasswordInterface
+   */
+  protected $originalPassword;
+
+  /**
+   * Indicates if MD5 password prefixing is enabled.
+   */
+  protected $enabled = FALSE;
+
+  /**
+   * Builds the replacement password service class.
+   *
+   * @param PasswordInterface $original_password
+   */
+  public function __construct(PasswordInterface $original_password) {
+    $this->originalPassword = $original_password;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function check($password, UserInterface $account) {
+    return $this->originalPassword->check($password, $account);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function userNeedsNewHash(UserInterface $account) {
+    return $this->originalPassword->userNeedsNewHash($account);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function hash($password) {
+    $hash = $this->originalPassword->hash($password);
+
+    // Allow prefixing only if the service was asked to prefix. Check also if
+    // the $password pattern is conforming to a MD5 result.
+    if ($this->enabled && preg_match('/^[0-9a-f]{32}$/', $password)) {
+      $hash = 'U' . $hash;
+    }
+
+    return $hash;
+  }
+
+  /**
+   * Enables the MD5 password prefixing.
+   */
+  public function enableMd5Prefixing() {
+    $this->enabled = TRUE;
+  }
+
+  /**
+   * Disables the MD5 password prefixing.
+   */
+  public function disableMd5Prefixing() {
+    $this->enabled = FALSE;
+  }
+
+}
diff --git a/core/modules/migrate/lib/Drupal/migrate/MigrateServiceProvider.php b/core/modules/migrate/lib/Drupal/migrate/MigrateServiceProvider.php
new file mode 100644
index 0000000..78a60bb
--- /dev/null
+++ b/core/modules/migrate/lib/Drupal/migrate/MigrateServiceProvider.php
@@ -0,0 +1,30 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\migrate\MigrateServiceProvider.
+ */
+
+namespace Drupal\migrate;
+
+use Drupal\Core\DependencyInjection\ServiceModifierInterface;
+use Drupal\Core\DependencyInjection\ContainerBuilder;
+
+/**
+ * Swaps the original 'password' service in order to handle password hashing for
+ * user migrations that have passwords hashed to MD5.
+ *
+ * @see \Drupal\migrate\MigratePassword
+ * @see \Drupal\Core\Password\PhpassHashedPassword
+ */
+class MigrateServiceProvider implements ServiceModifierInterface {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function alter(ContainerBuilder $container) {
+    $container->setDefinition('password_original', $container->getDefinition('password'));
+    $container->setDefinition('password', $container->getDefinition('password_migrate'));
+  }
+
+}
diff --git a/core/modules/migrate/lib/Drupal/migrate/MigrateSkipProcessException.php b/core/modules/migrate/lib/Drupal/migrate/MigrateSkipProcessException.php
new file mode 100644
index 0000000..0e64292
--- /dev/null
+++ b/core/modules/migrate/lib/Drupal/migrate/MigrateSkipProcessException.php
@@ -0,0 +1,15 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\migrate\MigrateSkipProcessException.
+ */
+
+namespace Drupal\migrate;
+
+/**
+ * This exception is thrown when the rest of the process should be skipped.
+ */
+class MigrateSkipProcessException extends \Exception {
+
+}
diff --git a/core/modules/migrate/lib/Drupal/migrate/MigrationStorageController.php b/core/modules/migrate/lib/Drupal/migrate/MigrationStorageController.php
new file mode 100644
index 0000000..1fd07f7
--- /dev/null
+++ b/core/modules/migrate/lib/Drupal/migrate/MigrationStorageController.php
@@ -0,0 +1,97 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\migrate\MigrateStorageController.
+ */
+
+namespace Drupal\migrate;
+
+use Drupal\Component\Graph\Graph;
+use Drupal\Core\Config\Entity\ConfigStorageController;
+
+/**
+ * Storage controller for migration entities.
+ */
+class MigrationStorageController extends ConfigStorageController implements MigrateBuildDependencyInterface {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function buildDependencyMigration(array $migrations, array $dynamic_ids) {
+    // Dependencies defined in the migration storage controller can be soft
+    // dependencies: if a soft dependency does not run, the current migration
+    // is still OK to go. This is indicated by adding ": false" (without
+    // quotes) after the name of the dependency. Hard dependencies (default)
+    // are called requirements. Both hard and soft dependencies (if run at
+    // all) must run before the current one.
+    $dependency_graph = array();
+    $requirement_graph = array();
+    $different = FALSE;
+    /** @var \Drupal\migrate\Entity\MigrationInterface $migration */
+    foreach ($migrations as $migration) {
+      $id = $migration->id();
+      $requirements[$id] = array();
+      $dependency_graph[$id]['edges'] = array();
+      if (isset($migration->dependencies) && is_array($migration->dependencies)) {
+        foreach ($migration->dependencies as $dependency) {
+          if (is_string($dependency) && !isset($dynamic_ids[$dependency])) {
+            $this->addDependency($requirement_graph, $id, $dependency, $dynamic_ids);
+          }
+          if (is_array($dependency)) {
+            list($dependency_string, $required) = each($dependency);
+            $dependency = $dependency_string;
+            if ($required) {
+              $this->addDependency($requirement_graph, $id, $dependency, $dynamic_ids);
+            }
+            else {
+              $different = TRUE;
+            }
+          }
+          $this->addDependency($dependency_graph, $id, $dependency, $dynamic_ids);
+        }
+      }
+    }
+    $graph_object = new Graph($dependency_graph);
+    $dependency_graph = $graph_object->searchAndSort();
+    if ($different) {
+      $graph_object = new Graph($requirement_graph);
+      $requirement_graph = $graph_object->searchAndSort();
+    }
+    else {
+      $requirement_graph = $dependency_graph;
+    }
+    $weights = array();
+    foreach ($migrations as $migration_id => $migration) {
+      // Populate a weights array to use with array_multisort later.
+      $weights[] = $dependency_graph[$migration_id]['weight'];
+      if (!empty($requirement_graph[$migration_id]['paths'])) {
+        $migration->set('requirements', $requirement_graph[$migration_id]['paths']);
+      }
+    }
+    array_multisort($weights, SORT_DESC, SORT_NUMERIC, $migrations);
+
+    return $migrations;
+  }
+
+  /**
+   * Add one or more dependencies to a graph.
+   *
+   * @param array $graph
+   *   The graph so far.
+   * @param int $id
+   *   The migration id.
+   * @param string $dependency
+   *   The dependency string.
+   * @param array $dynamic_ids
+   *   The dynamic id mapping.
+   */
+  protected function addDependency(array &$graph, $id, $dependency, $dynamic_ids) {
+    $dependencies = isset($dynamic_ids[$dependency]) ? $dynamic_ids[$dependency] : array($dependency);
+    if (!isset($graph[$id]['edges'])) {
+      $graph[$id]['edges'] = array();
+    }
+    $graph[$id]['edges'] += array_combine($dependencies, $dependencies);
+  }
+
+}
diff --git a/core/modules/migrate/lib/Drupal/migrate/Plugin/Derivative/MigrateEntity.php b/core/modules/migrate/lib/Drupal/migrate/Plugin/Derivative/MigrateEntity.php
new file mode 100644
index 0000000..df2c142
--- /dev/null
+++ b/core/modules/migrate/lib/Drupal/migrate/Plugin/Derivative/MigrateEntity.php
@@ -0,0 +1,76 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\migrate\Plugin\Derivative\MigrateEntity.
+ */
+
+namespace Drupal\migrate\Plugin\Derivative;
+
+use Drupal\Core\Plugin\Discovery\ContainerDerivativeInterface;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+
+class MigrateEntity implements ContainerDerivativeInterface {
+
+  /**
+   * List of derivative definitions.
+   *
+   * @var array
+   */
+  protected $derivatives = array();
+
+  /**
+   * The entity definitions
+   *
+   * @var \Drupal\Core\Entity\EntityTypeInterface[]
+   */
+  protected $entityDefinitions;
+
+  /**
+   * Constructs a MigrateEntity object.
+   *
+   * @param \Drupal\Core\Entity\EntityTypeInterface[] $entity_definitions
+   *   A list of entity definition objects.
+   */
+  public function __construct(array $entity_definitions) {
+    $this->entityDefinitions = $entity_definitions;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function create(ContainerInterface $container, $base_plugin_id) {
+    return new static(
+      $container->get('entity.manager')->getDefinitions()
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getDerivativeDefinition($derivative_id, array $base_plugin_definition) {
+    if (!empty($this->derivatives) && !empty($this->derivatives[$derivative_id])) {
+      return $this->derivatives[$derivative_id];
+    }
+    $this->getDerivativeDefinitions($base_plugin_definition);
+    return $this->derivatives[$derivative_id];
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getDerivativeDefinitions(array $base_plugin_definition) {
+    foreach ($this->entityDefinitions as $entity_type => $entity_info) {
+      $class = is_subclass_of($entity_info->getClass(), 'Drupal\Core\Config\Entity\ConfigEntityInterface') ?
+        'Drupal\migrate\Plugin\migrate\destination\EntityConfigBase' :
+        'Drupal\migrate\Plugin\migrate\destination\EntityContentBase';
+      $this->derivatives[$entity_type] = array(
+        'id' => "entity:$entity_type",
+        'class' => $class,
+        'requirements_met' => 1,
+      );
+    }
+    return $this->derivatives;
+  }
+
+}
diff --git a/core/modules/migrate/lib/Drupal/migrate/Plugin/Derivative/MigrateEntityRevision.php b/core/modules/migrate/lib/Drupal/migrate/Plugin/Derivative/MigrateEntityRevision.php
new file mode 100644
index 0000000..ae6395d
--- /dev/null
+++ b/core/modules/migrate/lib/Drupal/migrate/Plugin/Derivative/MigrateEntityRevision.php
@@ -0,0 +1,75 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\migrate\Plugin\Derivative\MigrateEntityDerivative.
+ */
+
+namespace Drupal\migrate\Plugin\Derivative;
+
+use Drupal\Core\Plugin\Discovery\ContainerDerivativeInterface;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+
+class MigrateEntityRevision implements ContainerDerivativeInterface {
+
+  /**
+   * List of derivative definitions.
+   *
+   * @var array
+   */
+  protected $derivatives = array();
+
+  /**
+   * The entity definitions
+   *
+   * @var \Drupal\Core\Entity\EntityTypeInterface[]
+   */
+  protected $entityDefinitions;
+
+  /**
+   * Constructs a MigrateEntity object.
+   *
+   * @param \Drupal\Core\Entity\EntityTypeInterface[] $entity_definitions
+   *   A list of entity definition objects.
+   */
+  public function __construct(array $entity_definitions) {
+    $this->entityDefinitions = $entity_definitions;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function create(ContainerInterface $container, $base_plugin_id) {
+    return new static(
+      $container->get('entity.manager')->getDefinitions()
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getDerivativeDefinition($derivative_id, array $base_plugin_definition) {
+    if (!empty($this->derivatives) && !empty($this->derivatives[$derivative_id])) {
+      return $this->derivatives[$derivative_id];
+    }
+    $this->getDerivativeDefinitions($base_plugin_definition);
+    return $this->derivatives[$derivative_id];
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getDerivativeDefinitions(array $base_plugin_definition) {
+    foreach ($this->entityDefinitions as $entity_type => $entity_info) {
+      if ($entity_info->getKey('revision')) {
+        $this->derivatives[$entity_type] = array(
+          'id' => "entity_revision:$entity_type",
+          'class' => 'Drupal\migrate\Plugin\migrate\destination\EntityRevision',
+          'requirements_met' => 1,
+        );
+      }
+    }
+    return $this->derivatives;
+  }
+
+}
diff --git a/core/modules/migrate/lib/Drupal/migrate/Plugin/MigrateDestinationInterface.php b/core/modules/migrate/lib/Drupal/migrate/Plugin/MigrateDestinationInterface.php
index 97ede97..a2c33f7 100644
--- a/core/modules/migrate/lib/Drupal/migrate/Plugin/MigrateDestinationInterface.php
+++ b/core/modules/migrate/lib/Drupal/migrate/Plugin/MigrateDestinationInterface.php
@@ -9,6 +9,7 @@
 
 use Drupal\Component\Plugin\PluginInspectionInterface;
 use Drupal\migrate\Entity\Migration;
+use Drupal\migrate\Entity\MigrationInterface;
 use Drupal\migrate\Row;
 
 /**
@@ -18,46 +19,85 @@
 interface MigrateDestinationInterface extends PluginInspectionInterface {
 
   /**
+   * Get the destination ids.
+   *
    * To support MigrateIdMap maps, derived destination classes should return
-   * schema field definition(s) corresponding to the primary key of the destination
-   * being implemented. These are used to construct the destination key fields
-   * of the map table for a migration using this destination.
+   * schema field definition(s) corresponding to the primary key of the
+   * destination being implemented. These are used to construct the destination
+   * key fields of the map table for a migration using this destination.
+   *
+   * @return array
+   *   An array of ids.
    */
-  public function getIdsSchema();
+  public function getIds();
 
   /**
+   * Returns an array of destination fields.
+   *
    * Derived classes must implement fields(), returning a list of available
    * destination fields.
    *
-   * @todo Review the cases where we need the Migration parameter, can we avoid that?
+   * @todo Review the cases where we need the Migration parameter,
+   * can we avoid that?
+   *
+   * @param \Drupal\migrate\Entity\MigrationInterface $migration
+   *   (optional) the migration containing this destination.
    *
-   * @param Migration $migration
-   *   Optionally, the migration containing this destination.
    * @return array
-   *  - Keys: machine names of the fields
-   *  - Values: Human-friendly descriptions of the fields.
+   *   - Keys: machine names of the fields
+   *   - Values: Human-friendly descriptions of the fields.
    */
-  public function fields(Migration $migration = NULL);
+  public function fields(MigrationInterface $migration = NULL);
+
 
   /**
-   * Derived classes may implement preImport() and/or postImport(), to do any
-   * processing they need done before or after looping over all source rows.
-   * Similarly, preRollback() or postRollback() may be implemented.
+   * Allows pre-processing of an import.
+   *
+   * Derived classes may implement preImport() to do any processing they need
+   * done before over all source rows.
    */
   public function preImport();
+
+  /**
+   * Allows pre-processing of a rollback.
+   */
   public function preRollback();
+
+  /**
+   * Allows post-processing of an import.
+   *
+   * Derived classes may implement postImport(), to do any processing they need
+   * done after looping over all source rows.
+   */
   public function postImport();
+
+  /**
+   * Allows post-processing of a rollback.
+   */
   public function postRollback();
 
   /**
-   * Derived classes must implement import(), to construct one new object (pre-populated
-   * using ID mappings in the Migration).
+   * Import the row.
+   *
+   * Derived classes must implement import(), to construct one new object
+   * (pre-populated) using ID mappings in the Migration).
+   *
+   * @param \Drupal\migrate\Row $row
+   *   The row object.
+   * @param array $old_destination_id_values
+   *   The old destination ids.
+   *
+   * @return mixed
+   *   The entity id or an indication of success.
    */
-  public function import(Row $row);
+  public function import(Row $row, array $old_destination_id_values = array());
 
   /**
    * Delete the specified IDs from the target Drupal.
+   *
    * @param array $destination_identifiers
+   *   The destination ids to delete.
    */
   public function rollbackMultiple(array $destination_identifiers);
+
 }
diff --git a/core/modules/migrate/lib/Drupal/migrate/Plugin/MigrateDestinationPluginManager.php b/core/modules/migrate/lib/Drupal/migrate/Plugin/MigrateDestinationPluginManager.php
new file mode 100644
index 0000000..d4d581b
--- /dev/null
+++ b/core/modules/migrate/lib/Drupal/migrate/Plugin/MigrateDestinationPluginManager.php
@@ -0,0 +1,67 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\migrate\Plugin\MigrateDestinationPluginManager.
+ */
+
+
+namespace Drupal\migrate\Plugin;
+
+use Drupal\Core\Cache\CacheBackendInterface;
+use Drupal\Core\Entity\EntityManagerInterface;
+use Drupal\Core\Extension\ModuleHandlerInterface;
+use Drupal\Core\Extension\ThemeHandlerInterface;
+use Drupal\Core\Language\LanguageManager;
+
+class MigrateDestinationPluginManager extends MigratePluginManager {
+
+  /**
+   * The theme handler
+   *
+   * @var \Drupal\Core\Extension\ThemeHandlerInterface
+   */
+  protected $themeHandler;
+
+  /**
+   * An associative array where the keys are the enabled modules and themes.
+   *
+   * @var array
+   */
+  protected $providers;
+
+  /**
+   * {@inheritdoc}
+   */
+  public function __construct($type, \Traversable $namespaces, CacheBackendInterface $cache_backend, LanguageManager $language_manager, ModuleHandlerInterface $module_handler, ThemeHandlerInterface $theme_handler, EntityManagerInterface $entity_manager, $annotation = 'Drupal\migrate\Annotation\MigrateDestination') {
+    parent::__construct($type, $namespaces, $cache_backend, $language_manager, $module_handler, $annotation);
+    $this->themeHandler = $theme_handler;
+    $this->entityManager = $entity_manager;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function processDefinition(&$definition, $plugin_id) {
+    // By setting requirements_met to something in the annotation, this
+    // handling can be skipped.
+    parent::processDefinition($definition, $plugin_id);
+    if ($definition['requirements_met'] === TRUE) {
+      if (substr($plugin_id, 0, 7) == 'entity:' && !$this->entityManager->getDefinition(substr($plugin_id, 7))) {
+        $definition['requirements_met'] = FALSE;
+      }
+      elseif (isset($definition['destination_provider'])) {
+        if (!isset($this->providers)) {
+          $this->providers = $this->moduleHandler->getModuleList();
+          foreach ($this->themeHandler->listInfo() as $theme => $info) {
+            if ($info->status) {
+              $this->providers[$theme] = TRUE;
+            }
+          }
+        }
+        $definition['requirements_met'] = isset($this->providers[$definition['destination_provider']]);
+      }
+    }
+  }
+
+}
diff --git a/core/modules/migrate/lib/Drupal/migrate/Plugin/MigrateEntityDestinationFieldInterface.php b/core/modules/migrate/lib/Drupal/migrate/Plugin/MigrateEntityDestinationFieldInterface.php
new file mode 100644
index 0000000..6082a21
--- /dev/null
+++ b/core/modules/migrate/lib/Drupal/migrate/Plugin/MigrateEntityDestinationFieldInterface.php
@@ -0,0 +1,28 @@
+<?php
+/**
+ * @file
+ * Contains
+ */
+
+namespace Drupal\migrate\Plugin;
+use Drupal\field\Entity\FieldInstance;
+
+/**
+ * Handle the importing of a specific configurable field type.
+ */
+interface MigrateEntityDestinationFieldInterface {
+
+  /**
+   * Convert an array of values into an array structure fit for entity_create.
+   *
+   * @param \Drupal\field\Entity\FieldInstance $instance
+   *   The field instance. For example, this can be used to check for required.
+   * @param array $values
+   *   The array of values.
+   * @return array|NULL
+   *   This will be set in the $values array passed to entity_create() as the
+   *   value of a configurable field of the type this class handles.
+   */
+  public function import(FieldInstance $instance, array $values = NULL);
+
+}
diff --git a/core/modules/migrate/lib/Drupal/migrate/Plugin/MigrateIdMapInterface.php b/core/modules/migrate/lib/Drupal/migrate/Plugin/MigrateIdMapInterface.php
index 4848b99..df392f0 100644
--- a/core/modules/migrate/lib/Drupal/migrate/Plugin/MigrateIdMapInterface.php
+++ b/core/modules/migrate/lib/Drupal/migrate/Plugin/MigrateIdMapInterface.php
@@ -18,7 +18,7 @@
  * Migrate ID mappings maintain a relation between source ID and destination ID
  * for audit and rollback purposes.
  */
-interface MigrateIdMapInterface extends PluginInspectionInterface {
+interface MigrateIdMapInterface extends \Iterator, PluginInspectionInterface {
 
   /**
    * Codes reflecting the current status of a map row.
@@ -201,7 +201,7 @@ public function lookupSourceID(array $destination_id_values);
    * Given a (possibly multi-field) source identifier value, return the
    * (possibly multi-field) destination identifier value it is mapped to.
    *
-   * @param array $destination_id_values
+   * @param array $source_id_values
    *   The source identifier values of the record.
    *
    * @return array
@@ -234,8 +234,9 @@ public function setMessage(MigrateMessageInterface $message);
   /**
    * Sets a specified record to be updated, if it exists.
    *
-   * @param $source_id_values
+   * @param array $source_id_values
    *   The source identifier values of the record.
    */
   public function setUpdate(array $source_id_values);
+
 }
diff --git a/core/modules/migrate/lib/Drupal/migrate/Plugin/MigratePluginManager.php b/core/modules/migrate/lib/Drupal/migrate/Plugin/MigratePluginManager.php
index 2fa236d..69b2d4f 100644
--- a/core/modules/migrate/lib/Drupal/migrate/Plugin/MigratePluginManager.php
+++ b/core/modules/migrate/lib/Drupal/migrate/Plugin/MigratePluginManager.php
@@ -8,11 +8,13 @@
 namespace Drupal\migrate\Plugin;
 
 use Drupal\Component\Plugin\Factory\DefaultFactory;
+use Drupal\Component\Utility\String;
 use Drupal\Core\Cache\CacheBackendInterface;
 use Drupal\Core\Extension\ModuleHandlerInterface;
 use Drupal\Core\Language\LanguageManager;
 use Drupal\Core\Plugin\DefaultPluginManager;
 use Drupal\migrate\Entity\MigrationInterface;
+use Drupal\migrate\MigrateException;
 
 /**
  * Manages migrate plugins.
@@ -54,9 +56,12 @@ public function createInstance($plugin_id, array $configuration = array(), Migra
     $plugin_class = DefaultFactory::getPluginClass($plugin_id, $plugin_definition);
     // If the plugin provides a factory method, pass the container to it.
     if (is_subclass_of($plugin_class, 'Drupal\Core\Plugin\ContainerFactoryPluginInterface')) {
-      return $plugin_class::create(\Drupal::getContainer(), $configuration, $plugin_id, $plugin_definition, $migration);
+      $plugin = $plugin_class::create(\Drupal::getContainer(), $configuration, $plugin_id, $plugin_definition, $migration);
     }
-    return new $plugin_class($configuration, $plugin_id, $plugin_definition, $migration);
+    else {
+      $plugin = new $plugin_class($configuration, $plugin_id, $plugin_definition, $migration);
+    }
+    return $plugin;
   }
 
 }
diff --git a/core/modules/migrate/lib/Drupal/migrate/Plugin/MigrateProcessPluginManager.php b/core/modules/migrate/lib/Drupal/migrate/Plugin/MigrateProcessPluginManager.php
new file mode 100644
index 0000000..aecb5f4
--- /dev/null
+++ b/core/modules/migrate/lib/Drupal/migrate/Plugin/MigrateProcessPluginManager.php
@@ -0,0 +1,42 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\migrate\Plugin\MigrateProcessPluginManager.
+ */
+
+namespace Drupal\migrate\Plugin;
+
+use Drupal\Core\Cache\CacheBackendInterface;
+use Drupal\Core\Extension\ModuleHandlerInterface;
+use Drupal\Core\Language\LanguageManager;
+use Drupal\migrate\Entity\MigrationInterface;
+
+class MigrateProcessPluginManager extends MigratePluginManager {
+
+  /**
+   * Plugin storage.
+   *
+   * @var array
+   */
+  protected $storage;
+
+  /**
+   * {@inheritdoc}
+   */
+  public function __construct($type, \Traversable $namespaces, CacheBackendInterface $cache_backend, LanguageManager $language_manager, ModuleHandlerInterface $module_handler, $annotation = 'Drupal\migrate\Annotation\MigrateProcessPlugin') {
+    parent::__construct($type, $namespaces, $cache_backend, $language_manager, $module_handler, $annotation);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function createInstance($plugin_id, array $configuration = array(), MigrationInterface $migration = NULL) {
+    $index = serialize($configuration);
+    if (!isset($this->storage[$migration->id()][$plugin_id][$index])) {
+      $this->storage[$migration->id()][$plugin_id][$index] = parent::createInstance($plugin_id, $configuration, $migration);
+    }
+    return $this->storage[$migration->id()][$plugin_id][$index];
+  }
+
+}
diff --git a/core/modules/migrate/lib/Drupal/migrate/Plugin/MigrateSourceInterface.php b/core/modules/migrate/lib/Drupal/migrate/Plugin/MigrateSourceInterface.php
index 60b59cf..da11d0b 100644
--- a/core/modules/migrate/lib/Drupal/migrate/Plugin/MigrateSourceInterface.php
+++ b/core/modules/migrate/lib/Drupal/migrate/Plugin/MigrateSourceInterface.php
@@ -23,7 +23,6 @@
    */
   public function fields();
 
-
   /**
    * Returns the iterator that will yield the row arrays to be processed.
    *
@@ -38,6 +37,7 @@ public function getIterator();
    * Add additional data to the row.
    *
    * @param \Drupal\Migrate\Row $row
+   *   The row object.
    *
    * @return bool
    *   FALSE if this row needs to be skipped.
@@ -45,4 +45,13 @@ public function getIterator();
   public function prepareRow(Row $row);
 
   public function __toString();
+
+  /**
+   * Get the source ids.
+   *
+   * @return array
+   *   The source ids.
+   */
+  public function getIds();
+
 }
diff --git a/core/modules/migrate/lib/Drupal/migrate/Plugin/RequirementsInterface.php b/core/modules/migrate/lib/Drupal/migrate/Plugin/RequirementsInterface.php
index ad45be5..8a5d816 100644
--- a/core/modules/migrate/lib/Drupal/migrate/Plugin/RequirementsInterface.php
+++ b/core/modules/migrate/lib/Drupal/migrate/Plugin/RequirementsInterface.php
@@ -15,7 +15,7 @@
   /**
    * Checks if requirements for this plugin are OK.
    *
-   * @return boolean
+   * @return bool
    *   TRUE if it is possible to use the plugin, FALSE if not.
    */
   public function checkRequirements();
diff --git a/core/modules/migrate/lib/Drupal/migrate/Plugin/SourceEntityInterface.php b/core/modules/migrate/lib/Drupal/migrate/Plugin/SourceEntityInterface.php
new file mode 100644
index 0000000..982ba3d
--- /dev/null
+++ b/core/modules/migrate/lib/Drupal/migrate/Plugin/SourceEntityInterface.php
@@ -0,0 +1,32 @@
+<?php
+/**
+ * @file
+ * Contains
+ */
+
+namespace Drupal\migrate\Plugin;
+
+/**
+ * Interface for sources providing an entity.
+ */
+interface SourceEntityInterface {
+
+  /**
+   * Whether this migration has a bundle migration.
+   *
+   * @return bool
+   *   TRUE when the bundle_migration key is required.
+   */
+  public function bundleMigrationRequired();
+
+  /**
+   * The entity type id (user, node etc).
+   *
+   * This function is used when bundleMigrationRequired() is FALSE.
+   *
+   * @return string
+   *   The entity type id.
+   */
+  public function entityTypeId();
+
+}
diff --git a/core/modules/migrate/lib/Drupal/migrate/Plugin/migrate/destination/ComponentEntityDisplayBase.php b/core/modules/migrate/lib/Drupal/migrate/Plugin/migrate/destination/ComponentEntityDisplayBase.php
new file mode 100644
index 0000000..a3bd8d0
--- /dev/null
+++ b/core/modules/migrate/lib/Drupal/migrate/Plugin/migrate/destination/ComponentEntityDisplayBase.php
@@ -0,0 +1,72 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\migrate\Plugin\migrate\destination\ComponentEntityDisplayBase.
+ */
+
+namespace Drupal\migrate\Plugin\migrate\destination;
+
+use Drupal\migrate\Entity\MigrationInterface;
+use Drupal\migrate\Row;
+
+abstract class ComponentEntityDisplayBase extends DestinationBase {
+
+  const MODE_NAME = '';
+
+  /**
+   * {@inheritdoc}
+   */
+  public function import(Row $row, array $old_destination_id_values = array()) {
+    $values = array();
+    // array_intersect_key() won't work because the order is important because
+    // this is also the return value.
+    foreach (array_keys($this->getIds()) as $id) {
+      $values[$id] = $row->getDestinationProperty($id);
+    }
+    $entity = $this->getEntity($values['entity_type'], $values['bundle'], $values[static::MODE_NAME]);
+    if (!$row->getDestinationProperty('hidden')) {
+      $entity
+        ->setComponent($values['field_name'], $row->getDestinationProperty('options') ?: array())
+        ->save();
+    }
+    else {
+      $entity->removeComponent($values['field_name']);
+    }
+    return array_values($values);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getIds() {
+    $ids['entity_type']['type'] = 'string';
+    $ids['bundle']['type'] = 'string';
+    $ids[static::MODE_NAME]['type'] = 'string';
+    $ids['field_name']['type'] = 'string';
+    return $ids;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function fields(MigrationInterface $migration = NULL) {
+    // TODO: Implement fields() method.
+  }
+
+  /**
+   * Get the entity.
+   *
+   * @param string $entity_type
+   *   The entity type to retrieve.
+   * @param string $bundle
+   *   The entity bundle.
+   * @param string $mode
+   *   The display mode.
+   *
+   * @return \Drupal\Core\Entity\Display\EntityDisplayInterface
+   *   The entity display object.
+   */
+  protected abstract function getEntity($entity_type, $bundle, $mode);
+
+}
diff --git a/core/modules/migrate/lib/Drupal/migrate/Plugin/migrate/destination/Config.php b/core/modules/migrate/lib/Drupal/migrate/Plugin/migrate/destination/Config.php
index 36ead84..7f69b31 100644
--- a/core/modules/migrate/lib/Drupal/migrate/Plugin/migrate/destination/Config.php
+++ b/core/modules/migrate/lib/Drupal/migrate/Plugin/migrate/destination/Config.php
@@ -1,13 +1,13 @@
 <?php
 /**
  * @file
- *   Provides Configuration Management destination plugin.
+ * Provides Configuration Management destination plugin.
  */
 
 namespace Drupal\migrate\Plugin\migrate\destination;
 
 use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
-use Drupal\migrate\Entity\Migration;
+use Drupal\migrate\Entity\MigrationInterface;
 use Drupal\migrate\MigrateException;
 use Drupal\migrate\Row;
 use Symfony\Component\DependencyInjection\ContainerInterface;
@@ -16,7 +16,9 @@
 /**
  * Persist data to the config system.
  *
- * @PluginID("d8_config")
+ * @MigrateDestination(
+ *   id = "config"
+ * )
  */
 class Config extends DestinationBase implements ContainerFactoryPluginInterface {
 
@@ -28,21 +30,33 @@ class Config extends DestinationBase implements ContainerFactoryPluginInterface
   protected $config;
 
   /**
+   * Constructs a Config destination object.
+   *
    * @param array $configuration
+   *   A configuration array containing information about the plugin instance.
    * @param string $plugin_id
+   *   The plugin ID for the plugin instance.
    * @param array $plugin_definition
-   * @param ConfigObject $config
+   *   The plugin implementation definition.
+   * @param \Drupal\migrate\Entity\MigrationInterface $migration
+   *   The migration entity.
+   * @param \Drupal\Core\Config\Config $config
+   *   The configuration object.
    */
-  public function __construct(array $configuration, $plugin_id, array $plugin_definition, ConfigObject $config) {
-    parent::__construct($configuration, $plugin_id, $plugin_definition);
+  public function __construct(array $configuration, $plugin_id, array $plugin_definition, MigrationInterface $migration, ConfigObject $config) {
+    parent::__construct($configuration, $plugin_id, $plugin_definition, $migration);
     $this->config = $config;
   }
 
-  public static function create(ContainerInterface $container, array $configuration, $plugin_id, array $plugin_definition) {
+  /**
+   * {@inheritdoc}
+   */
+  public static function create(ContainerInterface $container, array $configuration, $plugin_id, array $plugin_definition, MigrationInterface $migration = NULL) {
     return new static(
       $configuration,
       $plugin_id,
       $plugin_definition,
+      $migration,
       $container->get('config.factory')->get($configuration['config_name'])
     );
   }
@@ -50,14 +64,19 @@ public static function create(ContainerInterface $container, array $configuratio
   /**
    * {@inheritdoc}
    */
-  public function import(Row $row) {
-    $this->config
-      ->setData($row->getDestination())
-      ->save();
+  public function import(Row $row, array $old_destination_id_values = array()) {
+    foreach ($row->getRawDestination() as $key => $value) {
+      $this->config->set($key, $value);
+    }
+    $this->config->save();
+    return TRUE;
   }
 
   /**
+   * Throw an exception because config can not be rolled back.
+   *
    * @param array $destination_keys
+   *   The array of destination ids to roll back.
    *
    * @throws \Drupal\migrate\MigrateException
    */
@@ -66,22 +85,17 @@ public function rollbackMultiple(array $destination_keys) {
   }
 
   /**
-   * Derived classes must implement fields(), returning a list of available
-   * destination fields.
-   *
-   * @todo Review the cases where we need the Migration parameter, can we avoid that?
-   *
-   * @param Migration $migration
-   *   Optionally, the migration containing this destination.
-   * @return array
-   *  - Keys: machine names of the fields
-   *  - Values: Human-friendly descriptions of the fields.
+   * {@inheritdoc}
    */
-  public function fields(Migration $migration = NULL) {
+  public function fields(MigrationInterface $migration = NULL) {
     // @todo Dynamically fetch fields using Config Schema API.
   }
 
-  public function getIdsSchema() {
-    return array($this->config->getName() => array());
+  /**
+   * {@inheritdoc}
+   */
+  public function getIds() {
+    return array();
   }
+
 }
diff --git a/core/modules/migrate/lib/Drupal/migrate/Plugin/migrate/destination/DestinationBase.php b/core/modules/migrate/lib/Drupal/migrate/Plugin/migrate/destination/DestinationBase.php
index 7cdf11b..45e1df4 100644
--- a/core/modules/migrate/lib/Drupal/migrate/Plugin/migrate/destination/DestinationBase.php
+++ b/core/modules/migrate/lib/Drupal/migrate/Plugin/migrate/destination/DestinationBase.php
@@ -9,9 +9,42 @@
 namespace Drupal\migrate\Plugin\migrate\destination;
 
 use Drupal\Core\Plugin\PluginBase;
+use Drupal\migrate\Entity\MigrationInterface;
 use Drupal\migrate\Plugin\MigrateDestinationInterface;
+use Drupal\migrate\Plugin\RequirementsInterface;
 
-abstract class DestinationBase extends PluginBase implements MigrateDestinationInterface {
+abstract class DestinationBase extends PluginBase implements MigrateDestinationInterface, RequirementsInterface {
+
+  /**
+   * The migration.
+   *
+   * @var \Drupal\migrate\Entity\MigrationInterface
+   */
+  protected $migration;
+
+  /**
+   * Constructs an entity destination plugin.
+   *
+   * @param array $configuration
+   *   A configuration array containing information about the plugin instance.
+   * @param string $plugin_id
+   *   The plugin_id for the plugin instance.
+   * @param array $plugin_definition
+   *   The plugin implementation definition.
+   * @param MigrationInterface $migration
+   *   The migration.
+   */
+  public function __construct(array $configuration, $plugin_id, array $plugin_definition, MigrationInterface $migration) {
+    parent::__construct($configuration, $plugin_id, $plugin_definition);
+    $this->migration = $migration;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function checkRequirements() {
+    return $this->pluginDefinition['requirements_met'];
+  }
 
   /**
    * Modify the Row before it is imported.
@@ -27,27 +60,46 @@ public function preRollback() {
     // TODO: Implement preRollback() method.
   }
 
+  /**
+   * {@inheritdoc}
+   */
   public function postImport() {
     // TODO: Implement postImport() method.
   }
 
+  /**
+   * {@inheritdoc}
+   */
   public function postRollback() {
     // TODO: Implement postRollback() method.
   }
 
+  /**
+   * {@inheritdoc}
+   */
   public function rollbackMultiple(array $destination_identifiers) {
     // TODO: Implement rollbackMultiple() method.
   }
 
+  /**
+   * {@inheritdoc}
+   */
   public function getCreated() {
     // TODO: Implement getCreated() method.
   }
 
+  /**
+   * {@inheritdoc}
+   */
   public function getUpdated() {
     // TODO: Implement getUpdated() method.
   }
 
+  /**
+   * {@inheritdoc}
+   */
   public function resetStats() {
     // TODO: Implement resetStats() method.
   }
+
 }
diff --git a/core/modules/migrate/lib/Drupal/migrate/Plugin/migrate/destination/Entity.php b/core/modules/migrate/lib/Drupal/migrate/Plugin/migrate/destination/Entity.php
index 97e4121..ab8419b 100644
--- a/core/modules/migrate/lib/Drupal/migrate/Plugin/migrate/destination/Entity.php
+++ b/core/modules/migrate/lib/Drupal/migrate/Plugin/migrate/destination/Entity.php
@@ -9,16 +9,17 @@
 
 use Drupal\Core\Entity\EntityStorageControllerInterface;
 use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
-use Drupal\field\FieldInfo;
-use Drupal\migrate\Entity\Migration;
-use Drupal\migrate\Plugin\MigratePluginManager;
+use Drupal\migrate\Entity\MigrationInterface;
 use Drupal\migrate\Row;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
- * @PluginId("entity")
+ * @MigrateDestination(
+ *   id = "entity",
+ *   derivative = "Drupal\migrate\Plugin\Derivative\MigrateEntity"
+ * )
  */
-class Entity extends DestinationBase implements ContainerFactoryPluginInterface {
+abstract class Entity extends DestinationBase implements ContainerFactoryPluginInterface {
 
   /**
    * The entity storage controller.
@@ -28,57 +29,110 @@ class Entity extends DestinationBase implements ContainerFactoryPluginInterface
   protected $storageController;
 
   /**
-   * Constructs an entity destination plugin.
+   * The list of the bundles of this entity type.
    *
+   * @var array
+   */
+  protected $bundles;
+
+  /**
    * @param array $configuration
    *   A configuration array containing information about the plugin instance.
    * @param string $plugin_id
    *   The plugin_id for the plugin instance.
    * @param array $plugin_definition
    *   The plugin implementation definition.
+   * @param MigrationInterface $migration
+   *   The migration.
    * @param EntityStorageControllerInterface $storage_controller
    *   The storage controller for this entity type.
+   * @param array $bundles
+   *   The list of bundles this entity type has.
    */
-  public function __construct(array $configuration, $plugin_id, array $plugin_definition, EntityStorageControllerInterface $storage_controller) {
-    parent::__construct($configuration, $plugin_id, $plugin_definition);
+  public function __construct(array $configuration, $plugin_id, array $plugin_definition, MigrationInterface $migration, EntityStorageControllerInterface $storage_controller, array $bundles) {
+    parent::__construct($configuration, $plugin_id, $plugin_definition, $migration);
     $this->storageController = $storage_controller;
+    $this->bundles = $bundles;
   }
 
   /**
    * {@inheritdoc}
    */
-  public static function create(ContainerInterface $container, array $configuration, $plugin_id, array $plugin_definition) {
+  public static function create(ContainerInterface $container, array $configuration, $plugin_id, array $plugin_definition, MigrationInterface $migration = NULL) {
+    $entity_type = static::getEntityType($plugin_id);
     return new static(
       $configuration,
       $plugin_id,
       $plugin_definition,
-      $container->get('entity.manager')->getStorageController($configuration['entity_type'])
+      $migration,
+      $container->get('entity.manager')->getStorageController($entity_type),
+      array_keys($container->get('entity.manager')->getBundleInfo($entity_type))
     );
   }
 
   /**
-   * {@inheritdoc}
+   * Finds the entity type from configuration or plugin id.
+   *
+   * @param $configuration
+   *   The plugin configuration.
+   * @param $plugin_id
+   *   The plugin id.
+   *
+   * @return string
+   *   The entity type.
+   * @throws \Drupal\migrate\MigrateException
    */
-  public function import(Row $row) {
-    // @TODO: add field handling. https://drupal.org/node/2164451
-    // @TODO: add validation https://drupal.org/node/2164457
-    $entity = $this->storageController->create($row->getDestination());
-    $entity->save();
-    return array($entity->id());
+  protected static function getEntityType($plugin_id) {
+    // Remove entity:
+    return substr($plugin_id, 7);
   }
 
   /**
    * {@inheritdoc}
    */
-  public function getIdsSchema() {
-    // TODO: Implement getIdsSchema() method.
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function fields(Migration $migration = NULL) {
+  public function fields(MigrationInterface $migration = NULL) {
     // TODO: Implement fields() method.
   }
 
+  /**
+   * Creates or loads an entity.
+   *
+   * @param Row $row
+   * @return \Drupal\Core\Entity\EntityInterface
+   */
+  protected function getEntity(Row $row) {
+    $entity_id = $row->getDestinationProperty($this->getKey('id'));
+    if (!empty($entity_id) && ($entity = $this->storageController->load($entity_id))) {
+      $this->updateEntity($entity, $row);
+    }
+    else {
+      $values = $row->getDestination();
+      // Stubs might not have the bundle specified.
+      if ($row->stub()) {
+        $bundle_key = $this->getKey('bundle');
+        if ($bundle_key && !isset($values[$bundle_key])) {
+          $values[$bundle_key] = reset($this->bundles);
+        }
+      }
+      $entity = $this->storageController->create($values);
+      $entity->enforceIsNew();
+    }
+    return $entity;
+  }
+
+  /**
+   * Returns a specific entity key.
+   *
+   * @param string $key
+   *   The name of the entity key to return.
+   *
+   * @return string|bool
+   *   The entity key, or FALSE if it does not exist.
+   *
+   * @see \Drupal\Core\Entity\EntityTypeInterface::getKeys()
+   */
+  protected function getKey($key) {
+    return $this->storageController->getEntityType()->getKey($key);
+  }
+
 }
diff --git a/core/modules/migrate/lib/Drupal/migrate/Plugin/migrate/destination/EntityComment.php b/core/modules/migrate/lib/Drupal/migrate/Plugin/migrate/destination/EntityComment.php
new file mode 100644
index 0000000..36601d9
--- /dev/null
+++ b/core/modules/migrate/lib/Drupal/migrate/Plugin/migrate/destination/EntityComment.php
@@ -0,0 +1,91 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\migrate\Plugin\migrate\destination\EntityComment.
+ */
+
+namespace Drupal\migrate\Plugin\migrate\destination;
+
+use Drupal\Core\Entity\EntityStorageControllerInterface;
+use Drupal\Core\KeyValueStore\StateInterface;
+use Drupal\field\FieldInfo;
+use Drupal\migrate\Entity\MigrationInterface;
+use Drupal\migrate\Plugin\MigratePluginManager;
+use Drupal\migrate\Row;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+
+/**
+ * @MigrateDestination(
+ *   id = "entity:comment"
+ * )
+ */
+class EntityComment extends EntityContentBase {
+
+  /**
+   * The state storage object.
+   *
+   * @var \Drupal\Core\KeyValueStore\StateInterface
+   */
+  protected $state;
+
+  /**
+   * Builds an comment entity destination.
+   *
+   * @param array $configuration
+   *   A configuration array containing information about the plugin instance.
+   * @param string $plugin_id
+   *   The plugin_id for the plugin instance.
+   * @param array $plugin_definition
+   *   The plugin implementation definition.
+   * @param MigrationInterface $migration
+   *   The migration.
+   * @param EntityStorageControllerInterface $storage_controller
+   *   The storage controller for this entity type.
+   * @param array $bundles
+   *   The list of bundles this entity type has.
+   * @param \Drupal\migrate\Plugin\MigratePluginManager $plugin_manager
+   *   The migrate plugin manager.
+   * @param \Drupal\field\FieldInfo $field_info
+   *   The field and instance definitions service.
+   * @param \Drupal\Core\KeyValueStore\StateInterface $state
+   *   The state storage object.
+   */
+  public function __construct(array $configuration, $plugin_id, array $plugin_definition, MigrationInterface $migration, EntityStorageControllerInterface $storage_controller, array $bundles, MigratePluginManager $plugin_manager, FieldInfo $field_info, StateInterface $state) {
+    parent::__construct($configuration, $plugin_id, $plugin_definition, $migration, $storage_controller, $bundles, $plugin_manager, $field_info);
+    $this->state = $state;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function create(ContainerInterface $container, array $configuration, $plugin_id, array $plugin_definition, MigrationInterface $migration = NULL) {
+    $entity_type = static::getEntityType($plugin_id);
+    return new static(
+      $configuration,
+      $plugin_id,
+      $plugin_definition,
+      $migration,
+      $container->get('entity.manager')->getStorageController($entity_type),
+      array_keys($container->get('entity.manager')->getBundleInfo($entity_type)),
+      $container->get('plugin.manager.migrate.entity_field'),
+      $container->get('field.info'),
+      $container->get('state')
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function import(Row $row, array $old_destination_id_values = array()) {
+    if (($stub = !$row->getSourceProperty('entity_type')) && ($state = $this->state->get('comment.maintain_entity_statistics', 0))) {
+      $this->state->set('comment.maintain_entity_statistics', 0);
+    }
+    $return = parent::import($row, $old_destination_id_values);
+    if ($stub && $state) {
+      $this->state->set('comment.maintain_entity_statistics', $state);
+    }
+    return $return;
+  }
+
+}
diff --git a/core/modules/migrate/lib/Drupal/migrate/Plugin/migrate/destination/EntityConfigBase.php b/core/modules/migrate/lib/Drupal/migrate/Plugin/migrate/destination/EntityConfigBase.php
new file mode 100644
index 0000000..5220c02
--- /dev/null
+++ b/core/modules/migrate/lib/Drupal/migrate/Plugin/migrate/destination/EntityConfigBase.php
@@ -0,0 +1,117 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\migrate\Plugin\migrate\destination\EntityConfigBase.
+ */
+
+namespace Drupal\migrate\Plugin\migrate\destination;
+
+use Drupal\Component\Utility\NestedArray;
+use Drupal\Core\Entity\EntityInterface;
+use Drupal\migrate\Row;
+
+/**
+ * Class for importing configuration entities.
+ *
+ * This class serves as the import class for most configuration entities.
+ * It can be necessary to provide a specific entity class if the configuration
+ * entity has a compound id (see EntityFieldEntity) or it has specific setter
+ * methods (see EntityDateFormat). When implementing an entity destination for
+ * the latter case, make sure to add a test not only for importing but also
+ * for re-importing (if that is supported).
+ */
+class EntityConfigBase extends Entity {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function import(Row $row, array $old_destination_id_values = array()) {
+    $ids = $this->getIds();
+    $id_key = $this->getKey('id');
+    if (count($ids) > 1) {
+      $id_keys = array_keys($ids);
+      if (!$row->getDestinationProperty($id_key)) {
+        $row->setDestinationProperty($id_key, $this->generateId($row, $id_keys));
+      }
+    }
+    $entity = $this->getEntity($row);
+    $entity->save();
+    if (count($ids) > 1) {
+      // This can only be a config entity, content entities have their id key
+      // and that's it.
+      $return = array();
+      foreach ($id_keys as $id_key) {
+        $return[] = $entity->get($id_key);
+      }
+      return $return;
+    }
+    return array($entity->id());
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getIds() {
+    $id_key = $this->getKey('id');
+    $ids[$id_key]['type'] = 'string';
+    return $ids;
+  }
+
+
+  /**
+   * Updates an entity with the contents of a row.
+   *
+   * @param \Drupal\Core\Entity\EntityInterface $entity
+   *   The entity to update.
+   * @param \Drupal\migrate\Row $row
+   *   The row object to update from.
+   */
+  protected function updateEntity(EntityInterface $entity, Row $row) {
+    foreach ($row->getRawDestination() as $property => $value) {
+      $this->updateEntityProperty($entity, explode('.', $property), $value);
+    }
+  }
+
+  /**
+   * Updates a (possible nested) entity property with a value.
+   *
+   * @param \Drupal\Core\Entity\EntityInterface $entity
+   *   The config entity.
+   * @param array $parents
+   *   The array of parents.
+   * @param string|object $value
+   *   The value to update to.
+   */
+  protected function updateEntityProperty(EntityInterface $entity, array $parents, $value) {
+    $top_key = array_shift($parents);
+    $entity_value = $entity->get($top_key);
+    if (is_array($entity_value)) {
+      NestedArray::setValue($entity_value, $parents, $value);
+    }
+    else {
+      $entity_value = $value;
+    }
+    $entity->set($top_key, $entity_value);
+  }
+
+  /**
+   * Generate an entity id.
+   *
+   * @param Row $row
+   *   The current row.
+   * @param array $ids
+   *   The destination ids.
+   *
+   * @return string
+   *   The generated entity id.
+   */
+  protected function generateId(Row $row, array $ids) {
+    $id_values = array();
+    foreach ($ids as $id) {
+      $id_values[] = $row->getDestinationProperty($id);
+    }
+    return implode('.', $id_values);
+  }
+
+}
diff --git a/core/modules/migrate/lib/Drupal/migrate/Plugin/migrate/destination/EntityContentBase.php b/core/modules/migrate/lib/Drupal/migrate/Plugin/migrate/destination/EntityContentBase.php
new file mode 100644
index 0000000..f723dbf
--- /dev/null
+++ b/core/modules/migrate/lib/Drupal/migrate/Plugin/migrate/destination/EntityContentBase.php
@@ -0,0 +1,143 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\migrate\Plugin\migrate\destination\EntityBaseContent.
+ */
+
+namespace Drupal\migrate\Plugin\migrate\destination;
+
+use Drupal\Core\Entity\ContentEntityInterface;
+use Drupal\Core\Entity\EntityInterface;
+use Drupal\Core\Entity\EntityStorageControllerInterface;
+use Drupal\Core\TypedData\TypedDataInterface;
+use Drupal\field\FieldInfo;
+use Drupal\migrate\Entity\MigrationInterface;
+use Drupal\migrate\Plugin\MigratePluginManager;
+use Drupal\migrate\Row;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+
+/**
+ * The destination class for all content entities lacking a specific class.
+ */
+class EntityContentBase extends Entity {
+
+  /**
+   * @var \Drupal\field\FieldInfo
+   */
+  protected $fieldInfo;
+
+  /**
+   * Constructs a content entity.
+   *
+   * @param array $configuration
+   *   A configuration array containing information about the plugin instance.
+   * @param string $plugin_id
+   *   The plugin ID for the plugin instance.
+   * @param array $plugin_definition
+   *   The plugin implementation definition.
+   * @param \Drupal\migrate\Entity\MigrationInterface $migration
+   *   The migration entity.
+   * @param \Drupal\Core\Entity\EntityStorageControllerInterface $storage_controller
+   *   The storage controller for this entity type.
+   * @param array $bundles
+   *   The list of bundles this entity type has.
+   * @param \Drupal\migrate\Plugin\MigratePluginManager $plugin_manager
+   *   The plugin manager.
+   * @param \Drupal\Field\FieldInfo $field_info
+   *   The field info.
+   */
+  public function __construct(array $configuration, $plugin_id, array $plugin_definition, MigrationInterface $migration, EntityStorageControllerInterface $storage_controller, array $bundles, MigratePluginManager $plugin_manager, FieldInfo $field_info) {
+    parent::__construct($configuration, $plugin_id, $plugin_definition, $migration, $storage_controller, $bundles);
+    $this->migrateEntityFieldPluginManager = $plugin_manager;
+    $this->fieldInfo = $field_info;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function create(ContainerInterface $container, array $configuration, $plugin_id, array $plugin_definition, MigrationInterface $migration = NULL) {
+    $entity_type = static::getEntityType($plugin_id);
+    return new static(
+      $configuration,
+      $plugin_id,
+      $plugin_definition,
+      $migration,
+      $container->get('entity.manager')->getStorageController($entity_type),
+      array_keys($container->get('entity.manager')->getBundleInfo($entity_type)),
+      $container->get('plugin.manager.migrate.entity_field'),
+      $container->get('field.info')
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function import(Row $row, array $old_destination_id_values = array()) {
+    if ($all_instances = $this->fieldInfo->getInstances($this->storageController->getEntityTypeId())) {
+      /** @var \Drupal\Field\Entity\FieldInstanceConfig [] $instances */
+      $instances = array();
+      if ($bundle_key = $this->getKey('bundle')) {
+        $bundle = $row->getDestinationProperty($bundle_key);
+        if (isset($all_instances[$bundle])) {
+          $instances = $all_instances[$bundle];
+        }
+      }
+      foreach ($instances as $field_name => $instance) {
+        $field_type = $instance->getType();
+        if ($this->migrateEntityFieldPluginManager->getDefinition($field_type)) {
+          $destination_value = $this->migrateEntityFieldPluginManager->createInstance($field_type)->import($instance, $row->getDestinationProperty($field_name));
+          // @TODO: check for NULL return? Add an unset to $row? Maybe needed in
+          // exception handling? Propagate exception?
+          $row->setDestinationProperty($field_name, $destination_value);
+        }
+      }
+    }
+    $entity = $this->getEntity($row);
+    return $this->save($entity, $old_destination_id_values);
+  }
+
+  /**
+   * Save the entity.
+   *
+   * @param \Drupal\Core\Entity\ContentEntityInterface $entity
+   *   The content entity.
+   * @param array $old_destination_id_values
+   *   An array of destination id values.
+   *
+   * @return array
+   *   An array containing the entity id.
+   */
+  protected function save(ContentEntityInterface $entity, array $old_destination_id_values = array()) {
+    $entity->keepNewRevisionId(TRUE);
+    $entity->save();
+    return array($entity->id());
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getIds() {
+    $id_key = $this->getKey('id');
+    $ids[$id_key]['type'] = 'integer';
+    return $ids;
+  }
+
+  /**
+   * Update an entity with the new values from row.
+   *
+   * @param \Drupal\Core\Entity\EntityInterface $entity
+   *   The entity to update.
+   * @param \Drupal\migrate\Row $row
+   *   The row object to update from.
+   */
+  protected function updateEntity(EntityInterface $entity, Row $row) {
+    foreach ($row->getDestination() as $field_name => $values) {
+      $field = $entity->$field_name;
+      if ($field instanceof TypedDataInterface) {
+        $field->setValue($values);
+      }
+    }
+  }
+
+}
diff --git a/core/modules/migrate/lib/Drupal/migrate/Plugin/migrate/destination/EntityDateFormat.php b/core/modules/migrate/lib/Drupal/migrate/Plugin/migrate/destination/EntityDateFormat.php
new file mode 100644
index 0000000..5124ab0
--- /dev/null
+++ b/core/modules/migrate/lib/Drupal/migrate/Plugin/migrate/destination/EntityDateFormat.php
@@ -0,0 +1,34 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\migrate\Plugin\migrate\destination\EntityDateFormat.
+ */
+
+namespace Drupal\migrate\Plugin\migrate\destination;
+
+use Drupal\Core\Entity\EntityInterface;
+
+/**
+ * @MigrateDestination(
+ *   id = "entity:date_format"
+ * )
+ */
+class EntityDateFormat extends EntityConfigBase {
+
+  /**
+   * {@inheritdoc}
+   *
+   * @param \Drupal\system\DateFormatInterface $entity
+   *   The date entity.
+   */
+  protected function updateEntityProperty(EntityInterface $entity, array $parents, $value) {
+    if ($parents[0] == 'pattern') {
+      $entity->setPattern($value, $parents[1]);
+    }
+    else {
+      parent::updateEntityProperty($entity, $parents, $value);
+    }
+  }
+
+}
diff --git a/core/modules/migrate/lib/Drupal/migrate/Plugin/migrate/destination/EntityFieldConfig.php b/core/modules/migrate/lib/Drupal/migrate/Plugin/migrate/destination/EntityFieldConfig.php
new file mode 100644
index 0000000..8d2c312
--- /dev/null
+++ b/core/modules/migrate/lib/Drupal/migrate/Plugin/migrate/destination/EntityFieldConfig.php
@@ -0,0 +1,26 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\migrate\Plugin\migrate\destination\EntityFieldEntity.
+ */
+
+namespace Drupal\migrate\Plugin\migrate\destination;
+
+/**
+ * @MigrateDestination(
+ *   id = "entity:field_config"
+ * )
+ */
+class EntityFieldConfig extends EntityConfigBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getIds() {
+    $ids['entity_type']['type'] = 'string';
+    $ids['name']['type'] = 'string';
+    return $ids;
+  }
+
+}
diff --git a/core/modules/migrate/lib/Drupal/migrate/Plugin/migrate/destination/EntityFieldInstance.php b/core/modules/migrate/lib/Drupal/migrate/Plugin/migrate/destination/EntityFieldInstance.php
new file mode 100644
index 0000000..c02fef5
--- /dev/null
+++ b/core/modules/migrate/lib/Drupal/migrate/Plugin/migrate/destination/EntityFieldInstance.php
@@ -0,0 +1,29 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\migrate\Plugin\migrate\destination\EntityFieldInstance.
+ */
+
+namespace Drupal\migrate\Plugin\migrate\destination;
+
+use Drupal\migrate\Row;
+
+/**
+ * @MigrateDestination(
+ *   id = "entity:field_instance_config"
+ * )
+ */
+class EntityFieldInstance extends EntityConfigBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getIds() {
+    $ids['entity_type']['type'] = 'string';
+    $ids['bundle']['type'] = 'string';
+    $ids['field_name']['type'] = 'string';
+    return $ids;
+  }
+
+}
diff --git a/core/modules/migrate/lib/Drupal/migrate/Plugin/migrate/destination/EntityFile.php b/core/modules/migrate/lib/Drupal/migrate/Plugin/migrate/destination/EntityFile.php
new file mode 100644
index 0000000..4c8a1f1
--- /dev/null
+++ b/core/modules/migrate/lib/Drupal/migrate/Plugin/migrate/destination/EntityFile.php
@@ -0,0 +1,60 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\migrate\Plugin\migrate\destination\EntityFile.
+ */
+
+namespace Drupal\migrate\Plugin\migrate\destination;
+
+use Drupal\Core\Entity\EntityStorageControllerInterface;
+use Drupal\field\FieldInfo;
+use Drupal\migrate\Entity\MigrationInterface;
+use Drupal\migrate\Plugin\MigratePluginManager;
+use Drupal\migrate\Row;
+
+/**
+ * @MigrateDestination(
+ *   id = "entity:file"
+ * )
+ */
+class EntityFile extends EntityContentBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function __construct(array $configuration, $plugin_id, array $plugin_definition, MigrationInterface $migration, EntityStorageControllerInterface $storage_controller, array $bundles, MigratePluginManager $plugin_manager, FieldInfo $field_info) {
+    $configuration += array(
+      'source_base_path' => '',
+      'source_path_property' => 'filepath',
+      'destination_path_property' => 'uri',
+      'move' => FALSE,
+    );
+    parent::__construct($configuration, $plugin_id, $plugin_definition, $migration, $storage_controller, $bundles, $plugin_manager, $field_info);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function import(Row $row, array $old_destination_id_values = array()) {
+    $source = $this->configuration['source_base_path'] . $row->getSourceProperty($this->configuration['source_path_property']);
+    $destination = $row->getDestinationProperty($this->configuration['destination_path_property']);
+    $replace = FILE_EXISTS_REPLACE;
+    if (!empty($this->configuration['rename'])) {
+      $entity_id = $row->getDestinationProperty($this->getKey('id'));
+      if (!empty($entity_id) && ($entity = $this->storageController->load($entity_id))) {
+        $replace = FILE_EXISTS_RENAME;
+      }
+    }
+    $dirname = drupal_dirname($destination);
+    file_prepare_directory($dirname, FILE_CREATE_DIRECTORY);
+    if ($this->configuration['move']) {
+      file_unmanaged_move($source, $destination, $replace);
+    }
+    else {
+      file_unmanaged_copy($source, $destination, $replace);
+    }
+    return parent::import($row, $old_destination_id_values);
+  }
+
+}
diff --git a/core/modules/migrate/lib/Drupal/migrate/Plugin/migrate/destination/EntityRevision.php b/core/modules/migrate/lib/Drupal/migrate/Plugin/migrate/destination/EntityRevision.php
new file mode 100644
index 0000000..b6f2ebe
--- /dev/null
+++ b/core/modules/migrate/lib/Drupal/migrate/Plugin/migrate/destination/EntityRevision.php
@@ -0,0 +1,75 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\migrate\Plugin\migrate\destination\EntityRevision.
+ */
+
+namespace Drupal\migrate\Plugin\migrate\destination;
+
+use Drupal\Core\Entity\ContentEntityInterface;
+use Drupal\migrate\MigrateException;
+use Drupal\migrate\Row;
+
+/**
+ * @MigrateDestination(
+ *   id = "entity_revision",
+ *   derivative = "Drupal\migrate\Plugin\Derivative\MigrateEntityRevision"
+ * )
+ */
+class EntityRevision extends EntityContentBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  protected static function getEntityType($plugin_id) {
+    // Remove entity_revision:
+    return substr($plugin_id, 16);
+  }
+
+  /**
+   * Get the entity.
+   *
+   * @param \Drupal\migrate\Row $row
+   *   The row object.
+   *
+   * @return \Drupal\Core\Entity\EntityInterface|false
+   *   The entity or false if it can not be created.
+   */
+  protected function getEntity(Row $row) {
+    $revision_id = $row->getDestinationProperty($this->getKey('revision'));
+   if (!empty($revision_id) && ($entity = $this->storageController->loadRevision($revision_id))) {
+      $entity->setNewRevision(FALSE);
+    }
+    else {
+      $entity_id = $row->getDestinationProperty($this->getKey('id'));
+      $entity = $this->storageController->load($entity_id);
+      $entity->enforceIsNew(FALSE);
+      $entity->setNewRevision(TRUE);
+      $entity->keepNewRevisionId(TRUE);
+    }
+    $this->updateEntity($entity, $row);
+    $entity->isDefaultRevision(FALSE);
+    return $entity;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function save(ContentEntityInterface $entity, array $old_destination_id_values = array()) {
+    $entity->save();
+    return array($entity->getRevisionId());
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getIds() {
+    if ($key = $this->getKey('revision')) {
+      $ids[$key]['type'] = 'integer';
+      return $ids;
+    }
+    throw new MigrateException('This entity type does not support revisions.');
+  }
+
+}
diff --git a/core/modules/migrate/lib/Drupal/migrate/Plugin/migrate/destination/EntitySearchPage.php b/core/modules/migrate/lib/Drupal/migrate/Plugin/migrate/destination/EntitySearchPage.php
new file mode 100644
index 0000000..0e623ef
--- /dev/null
+++ b/core/modules/migrate/lib/Drupal/migrate/Plugin/migrate/destination/EntitySearchPage.php
@@ -0,0 +1,33 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\migrate\Plugin\migrate\destination\EntitySearchPage.
+ */
+
+namespace Drupal\migrate\Plugin\migrate\destination;
+
+use Drupal\Core\Entity\EntityInterface;
+use Drupal\migrate\Row;
+
+/**
+ * @MigrateDestination(
+ *   id = "entity:search_page"
+ * )
+ */
+class EntitySearchPage extends EntityConfigBase {
+
+  /**
+   * Updates the entity with the contents of a row.
+   *
+   * @param \Drupal\Core\Entity\EntityInterface $entity
+   *   The search page entity.
+   * @param \Drupal\migrate\Row $row
+   *   The row object to update from.
+   */
+  protected function updateEntity(EntityInterface $entity, Row $row) {
+    $entity->setPlugin($row->getDestinationProperty('plugin'));
+    $entity->getPlugin()->setConfiguration($row->getDestinationProperty('configuration'));
+  }
+
+}
diff --git a/core/modules/migrate/lib/Drupal/migrate/Plugin/migrate/destination/EntityUser.php b/core/modules/migrate/lib/Drupal/migrate/Plugin/migrate/destination/EntityUser.php
new file mode 100644
index 0000000..3b3c5b1
--- /dev/null
+++ b/core/modules/migrate/lib/Drupal/migrate/Plugin/migrate/destination/EntityUser.php
@@ -0,0 +1,102 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\migrate\Plugin\migrate\destination\EntityUser.
+ */
+
+namespace Drupal\migrate\Plugin\migrate\destination;
+
+use Drupal\Core\Entity\EntityStorageControllerInterface;
+use Drupal\Core\Password\PasswordInterface;
+use Drupal\field\FieldInfo;
+use Drupal\migrate\Entity\MigrationInterface;
+use Drupal\migrate\MigrateException;
+use Drupal\migrate\MigratePassword;
+use Drupal\migrate\Plugin\MigratePluginManager;
+use Drupal\migrate\Row;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+
+/**
+ * @MigrateDestination(
+ *   id = "entity:user"
+ * )
+ */
+class EntityUser extends EntityContentBase {
+
+  /**
+   * The password service class.
+   *
+   * @var \Drupal\Core\Password\PasswordInterface
+   */
+  protected $password;
+
+  /**
+   * Builds an user entity destination.
+   *
+   * @param array $configuration
+   *   A configuration array containing information about the plugin instance.
+   * @param string $plugin_id
+   *   The plugin_id for the plugin instance.
+   * @param array $plugin_definition
+   *   The plugin implementation definition.
+   * @param MigrationInterface $migration
+   *   The migration.
+   * @param EntityStorageControllerInterface $storage_controller
+   *   The storage controller for this entity type.
+   * @param array $bundles
+   *   The list of bundles this entity type has.
+   * @param \Drupal\migrate\Plugin\MigratePluginManager $plugin_manager
+   *   The migrate plugin manager.
+   * @param \Drupal\field\FieldInfo $field_info
+   *   The field and instance definitions service.
+   * @param \Drupal\Core\Password\PasswordInterface $password
+   *   The password service.
+   */
+  public function __construct(array $configuration, $plugin_id, array $plugin_definition, MigrationInterface $migration, EntityStorageControllerInterface $storage_controller, array $bundles, MigratePluginManager $plugin_manager, FieldInfo $field_info, PasswordInterface $password) {
+    parent::__construct($configuration, $plugin_id, $plugin_definition, $migration, $storage_controller, $bundles, $plugin_manager, $field_info);
+    if (isset($configuration['md5_passwords'])) {
+      $this->password = $password;
+    }
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function create(ContainerInterface $container, array $configuration, $plugin_id, array $plugin_definition, MigrationInterface $migration = NULL) {
+    $entity_type = static::getEntityType($plugin_id);
+    return new static(
+      $configuration,
+      $plugin_id,
+      $plugin_definition,
+      $migration,
+      $container->get('entity.manager')->getStorageController($entity_type),
+      array_keys($container->get('entity.manager')->getBundleInfo($entity_type)),
+      $container->get('plugin.manager.migrate.entity_field'),
+      $container->get('field.info'),
+      $container->get('password')
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   * @throws \Drupal\migrate\MigrateException
+   */
+  public function import(Row $row, array $old_destination_id_values = array()) {
+    if ($this->password) {
+      if ($this->password instanceof MigratePassword) {
+        $this->password->enableMd5Prefixing();
+      }
+      else {
+        throw new MigrateException('Password service has been altered by another module, aborting.');
+      }
+    }
+    $ids = parent::import($row, $old_destination_id_values);
+    if ($this->password) {
+      $this->password->disableMd5Prefixing();
+    }
+
+    return $ids;
+  }
+
+}
diff --git a/core/modules/migrate/lib/Drupal/migrate/Plugin/migrate/destination/EntityViewMode.php b/core/modules/migrate/lib/Drupal/migrate/Plugin/migrate/destination/EntityViewMode.php
new file mode 100644
index 0000000..0887d30
--- /dev/null
+++ b/core/modules/migrate/lib/Drupal/migrate/Plugin/migrate/destination/EntityViewMode.php
@@ -0,0 +1,26 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\migrate\Plugin\migrate\destination\EntityViewMode.
+ */
+
+namespace Drupal\migrate\Plugin\migrate\destination;
+
+/**
+ * @MigrateDestination(
+ *   id = "entity:view_mode"
+ * )
+ */
+class EntityViewMode extends EntityConfigBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getIds() {
+    $ids['targetEntityType']['type'] = 'string';
+    $ids['mode']['type'] = 'string';
+    return $ids;
+  }
+
+}
diff --git a/core/modules/migrate/lib/Drupal/migrate/Plugin/migrate/destination/PerComponentEntityDisplay.php b/core/modules/migrate/lib/Drupal/migrate/Plugin/migrate/destination/PerComponentEntityDisplay.php
new file mode 100644
index 0000000..953d5ff
--- /dev/null
+++ b/core/modules/migrate/lib/Drupal/migrate/Plugin/migrate/destination/PerComponentEntityDisplay.php
@@ -0,0 +1,28 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\migrate\Plugin\migrate\destination\PerComponentEntityDisplay.
+ */
+
+namespace Drupal\migrate\Plugin\migrate\destination;
+
+/**
+ * This class imports one component of an entity display.
+ *
+ * @MigrateDestination(
+ *   id = "component_entity_display"
+ * )
+ */
+class PerComponentEntityDisplay extends ComponentEntityDisplayBase {
+
+  const MODE_NAME = 'view_mode';
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function getEntity($entity_type, $bundle, $view_mode) {
+    return entity_get_display($entity_type, $bundle, $view_mode);
+  }
+
+}
diff --git a/core/modules/migrate/lib/Drupal/migrate/Plugin/migrate/destination/PerComponentEntityFormDisplay.php b/core/modules/migrate/lib/Drupal/migrate/Plugin/migrate/destination/PerComponentEntityFormDisplay.php
new file mode 100644
index 0000000..7ae9d46
--- /dev/null
+++ b/core/modules/migrate/lib/Drupal/migrate/Plugin/migrate/destination/PerComponentEntityFormDisplay.php
@@ -0,0 +1,28 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\migrate\Plugin\migrate\destination\PerComponentEntityFormDisplay.
+ */
+
+namespace Drupal\migrate\Plugin\migrate\destination;
+
+/**
+ * This class imports one component of an entity form display.
+ *
+ * @MigrateDestination(
+ *   id = "component_entity_form_display"
+ * )
+ */
+class PerComponentEntityFormDisplay extends ComponentEntityDisplayBase {
+
+  const MODE_NAME = 'form_mode';
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function getEntity($entity_type, $bundle, $form_mode) {
+    return entity_get_form_display($entity_type, $bundle, $form_mode);
+  }
+
+}
diff --git a/core/modules/migrate/lib/Drupal/migrate/Plugin/migrate/destination/UrlAlias.php b/core/modules/migrate/lib/Drupal/migrate/Plugin/migrate/destination/UrlAlias.php
new file mode 100644
index 0000000..e2c1403
--- /dev/null
+++ b/core/modules/migrate/lib/Drupal/migrate/Plugin/migrate/destination/UrlAlias.php
@@ -0,0 +1,92 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\migrate\Plugin\migrate\destination\UrlAlias.
+ */
+
+namespace Drupal\migrate\Plugin\migrate\destination;
+
+use Drupal\migrate\Entity\MigrationInterface;
+use Drupal\migrate\Row;
+use Drupal\Core\Path\Path;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
+
+/**
+ * @MigrateDestination(
+ *   id = "url_alias"
+ * )
+ */
+class UrlAlias extends DestinationBase implements ContainerFactoryPluginInterface {
+
+  /**
+   * The path crud service.
+   *
+   * @var Path $path
+   */
+  protected $path;
+
+  /**
+   * Constructs an entity destination plugin.
+   *
+   * @param array $configuration
+   *   A configuration array containing information about the plugin instance.
+   * @param string $plugin_id
+   *   The plugin_id for the plugin instance.
+   * @param array $plugin_definition
+   *   The plugin implementation definition.
+   * @param MigrationInterface $migration
+   *   The migration.
+   * @param \Drupal\Core\Path\Path $path
+   *   The path crud service.
+   */
+  public function __construct(array $configuration, $plugin_id, array $plugin_definition, MigrationInterface $migration, Path $path) {
+    parent::__construct($configuration, $plugin_id, $plugin_definition, $migration);
+    $this->path = $path;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function create(ContainerInterface $container, array $configuration, $plugin_id, array $plugin_definition, MigrationInterface $migration = NULL) {
+    return new static(
+      $configuration,
+      $plugin_id,
+      $plugin_definition,
+      $migration,
+      $container->get('path.crud')
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function import(Row $row, array $old_destination_id_values = array()) {
+
+    $path = $this->path->save(
+      $row->getDestinationProperty('source'),
+      $row->getDestinationProperty('alias'),
+      $row->getDestinationProperty('langcode'),
+      $old_destination_id_values ? $old_destination_id_values[0] : NULL
+    );
+
+    return array($path['pid']);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getIds() {
+    $ids['pid']['type'] = 'integer';
+    return $ids;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function fields(MigrationInterface $migration = NULL) {
+    // TODO: Implement fields() method.
+  }
+
+}
diff --git a/core/modules/migrate/lib/Drupal/migrate/Plugin/migrate/id_map/Sql.php b/core/modules/migrate/lib/Drupal/migrate/Plugin/migrate/id_map/Sql.php
index fa731ff..b9988e9 100644
--- a/core/modules/migrate/lib/Drupal/migrate/Plugin/migrate/id_map/Sql.php
+++ b/core/modules/migrate/lib/Drupal/migrate/Plugin/migrate/id_map/Sql.php
@@ -8,11 +8,12 @@
 namespace Drupal\migrate\Plugin\migrate\id_map;
 
 use Drupal\Component\Utility\Unicode;
+use Drupal\Core\Database\Connection;
+use Drupal\Core\Field\FieldDefinition;
 use Drupal\Core\Plugin\PluginBase;
 use Drupal\migrate\Entity\MigrationInterface;
 use Drupal\migrate\MigrateException;
 use Drupal\migrate\MigrateMessageInterface;
-use Drupal\migrate\Plugin\migrate\source\SqlBase;
 use Drupal\migrate\Plugin\MigrateIdMapInterface;
 use Drupal\migrate\Row;
 
@@ -74,13 +75,11 @@ class Sql extends PluginBase implements MigrateIdMapInterface {
   protected $destinationIdFields;
 
   /**
-   * Stores whether the the tables (map/message) already exist.
-   *
-   * This is determined just once per request/instance of the class.
+   * Whether the plugin is already initialized.
    *
    * @var boolean
    */
-  protected $ensured;
+  protected $initialized;
 
   /**
    * The result.
@@ -90,6 +89,20 @@ class Sql extends PluginBase implements MigrateIdMapInterface {
   protected $result = NULL;
 
   /**
+   * The source identifiers.
+   *
+   * @var array
+   */
+  protected $sourceIds = array();
+
+  /**
+   * The destination identifiers.
+   *
+   * @var array
+   */
+  protected $destinationIds = array();
+
+  /**
    * The current row.
    *
    * @var null
@@ -121,29 +134,41 @@ public function __construct(array $configuration, $plugin_id, array $plugin_defi
     parent::__construct($configuration, $plugin_id, $plugin_definition);
 
     $this->migration = $migration;
-    $machine_name = $migration->id();
+  }
 
-    // Default generated table names, limited to 63 characters.
-    $prefixLength = strlen($this->getDatabase()->tablePrefix()) ;
-    $this->mapTableName = 'migrate_map_' . Unicode::strtolower($machine_name);
-    $this->mapTableName = Unicode::substr($this->mapTableName, 0, 63 - $prefixLength);
-    $this->messageTableName = 'migrate_message_' . Unicode::strtolower($machine_name);
-    $this->messageTableName = Unicode::substr($this->messageTableName, 0, 63 - $prefixLength);
-    $this->sourceIds = $migration->get('sourceIds');
-    $this->destinationIds = $migration->get('destinationIds');
+  /**
+   * The source ID fields.
+   *
+   * @return array
+   *   The source ID fields.
+   */
+  protected function sourceIdFields() {
+    if (!isset($this->sourceIdFields)) {
+      // Build the source and destination identifier maps.
+      $this->sourceIdFields = array();
+      $count = 1;
+      foreach ($this->migration->getSourcePlugin()->getIds() as $field => $schema) {
+        $this->sourceIdFields[$field] = 'sourceid' . $count++;
+      }
+    }
+    return $this->sourceIdFields;
+  }
 
-    // Build the source and destination identifier maps.
-    $this->sourceIdFields = array();
-    $count = 1;
-    foreach ($this->sourceIds as $field => $schema) {
-      $this->sourceIdFields[$field] = 'sourceid' . $count++;
+  /**
+   * The destination ID fields.
+   *
+   * @return array
+   *   The destination ID fields.
+   */
+  protected function destinationIdFields() {
+    if (!isset($this->destinationIdFields)) {
+      $this->destinationIdFields = array();
+      $count = 1;
+      foreach ($this->migration->getDestinationPlugin()->getIds() as $field => $schema) {
+        $this->destinationIdFields[$field] = 'destid' . $count++;
+      }
     }
-    $this->destinationIdFields = array();
-    $count = 1;
-    foreach ($this->destinationIds as $field => $schema) {
-      $this->destinationIdFields[$field] = 'destid' . $count++;
-    }
-    $this->ensureTables();
+    return $this->destinationIdFields;
   }
 
   /**
@@ -151,7 +176,8 @@ public function __construct(array $configuration, $plugin_id, array $plugin_defi
    *
    * @return string
    */
-  public function getMapTableName() {
+  public function mapTableName() {
+    $this->init();
     return $this->mapTableName;
   }
 
@@ -160,29 +186,19 @@ public function getMapTableName() {
    *
    * @return string
    */
-  public function getMessageTableName() {
+  public function messageTableName() {
+    $this->init();
     return $this->messageTableName;
   }
 
   /**
-   * Qualifying the map table name with the database name makes cross-db joins
-   * possible. Note that, because prefixes are applied after we do this (i.e.,
-   * it will prefix the string we return), we do not qualify the table if it has
-   * a prefix. This will work fine when the source data is in the default
-   * (prefixed) database (in particular, for simpletest), but not if the primary
-   * query is in an external database.
-   *
    * @return string
    */
   public function getQualifiedMapTableName() {
-    $options = $this->getDatabase()->getConnectionOptions();
-    $prefix = $this->getDatabase()->tablePrefix($this->mapTableName);
-    if ($prefix) {
-      return $this->mapTableName;
-    }
-    else {
-      return $options['database'] . '.' . $this->mapTableName;
-    }
+    $database = $this->getDatabase();
+    $options = $database->getConnectionOptions();
+    $prefix = $database->tablePrefix($this->mapTableName);
+    return $options['database'] . '.' . $prefix . $this->mapTableName;
   }
 
   /**
@@ -192,12 +208,30 @@ public function getQualifiedMapTableName() {
    */
   protected function getDatabase() {
     if (!isset($this->database)) {
-      $this->database = SqlBase::getDatabaseConnection($this->migration->id(), $this->configuration);
+      $this->database = \Drupal::database();
     }
+    $this->init();
     return $this->database;
   }
 
   /**
+   * Initialize the plugin.
+   */
+  protected function init() {
+    if (!$this->initialized) {
+      $this->initialized = TRUE;
+      // Default generated table names, limited to 63 characters.
+      $machine_name = str_replace(':', '__', $this->migration->id());
+      $prefixLength = strlen($this->getDatabase()->tablePrefix()) ;
+      $this->mapTableName = 'migrate_map_' . Unicode::strtolower($machine_name);
+      $this->mapTableName = Unicode::substr($this->mapTableName, 0, 63 - $prefixLength);
+      $this->messageTableName = 'migrate_message_' . Unicode::strtolower($machine_name);
+      $this->messageTableName = Unicode::substr($this->messageTableName, 0, 63 - $prefixLength);
+      $this->ensureTables();
+    }
+  }
+
+  /**
    * {@inheritdoc}
    */
   public function setMessage(MigrateMessageInterface $message) {
@@ -208,133 +242,148 @@ public function setMessage(MigrateMessageInterface $message) {
    * Create the map and message tables if they don't already exist.
    */
   protected function ensureTables() {
-    if (!$this->ensured) {
-      if (!$this->getDatabase()->schema()->tableExists($this->mapTableName)) {
-        // Generate appropriate schema info for the map and message tables,
-        // and map from the source field names to the map/msg field names.
-        $count = 1;
-        $source_id_schema = array();
-        $pks = array();
-        foreach ($this->sourceIds as $field_schema) {
-          $mapkey = 'sourceid' . $count++;
-          $source_id_schema[$mapkey] = $field_schema;
-          $pks[] = $mapkey;
-        }
+    if (!$this->getDatabase()->schema()->tableExists($this->mapTableName)) {
+      // Generate appropriate schema info for the map and message tables,
+      // and map from the source field names to the map/msg field names.
+      $count = 1;
+      $source_id_schema = array();
+      $pks = array();
+      foreach ($this->migration->getSourcePlugin()->getIds() as $id_definition) {
+        $mapkey = 'sourceid' . $count++;
+        $source_id_schema[$mapkey] = $this->getFieldSchema($id_definition);
+        $pks[] = $mapkey;
+      }
 
-        $fields = $source_id_schema;
+      $fields = $source_id_schema;
 
-        // Add destination identifiers to map table.
-        // TODO: How do we discover the destination schema?
-        $count = 1;
-        foreach ($this->destinationIds as $field_schema) {
-          // Allow dest identifier fields to be NULL (for IGNORED/FAILED
-          // cases).
-          $field_schema['not null'] = FALSE;
-          $mapkey = 'destid' . $count++;
-          $fields[$mapkey] = $field_schema;
-        }
-        $fields['source_row_status'] = array(
+      // Add destination identifiers to map table.
+      // TODO: How do we discover the destination schema?
+      $count = 1;
+      foreach ($this->migration->getDestinationPlugin()->getIds() as $id_definition) {
+        // Allow dest identifier fields to be NULL (for IGNORED/FAILED
+        // cases).
+        $mapkey = 'destid' . $count++;
+        $fields[$mapkey] = $this->getFieldSchema($id_definition);
+        $fields[$mapkey]['not null'] = FALSE;
+      }
+      $fields['source_row_status'] = array(
+        'type' => 'int',
+        'size' => 'tiny',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'default' => MigrateIdMapInterface::STATUS_IMPORTED,
+        'description' => 'Indicates current status of the source row',
+      );
+      $fields['rollback_action'] = array(
+        'type' => 'int',
+        'size' => 'tiny',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'default' => MigrateIdMapInterface::ROLLBACK_DELETE,
+        'description' => 'Flag indicating what to do for this item on rollback',
+      );
+      $fields['last_imported'] = array(
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'default' => 0,
+        'description' => 'UNIX timestamp of the last time this row was imported',
+      );
+      $fields['hash'] = array(
+        'type' => 'varchar',
+        'length' => '64',
+        'not null' => FALSE,
+        'description' => 'Hash of source row data, for detecting changes',
+      );
+      $schema = array(
+        'description' => 'Mappings from source identifier value(s) to destination identifier value(s).',
+        'fields' => $fields,
+      );
+      if ($pks) {
+        $schema['primary key'] = $pks;
+      }
+      $this->getDatabase()->schema()->createTable($this->mapTableName, $schema);
+
+      // Now do the message table.
+      $fields = array();
+      $fields['msgid'] = array(
+        'type' => 'serial',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+      );
+      $fields += $source_id_schema;
+
+      $fields['level'] = array(
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'default' => 1,
+      );
+      $fields['message'] = array(
+        'type' => 'text',
+        'size' => 'medium',
+        'not null' => TRUE,
+      );
+      $schema = array(
+        'description' => 'Messages generated during a migration process',
+        'fields' => $fields,
+        'primary key' => array('msgid'),
+      );
+      if ($pks) {
+        $schema['indexes']['sourcekey'] = $pks;
+      }
+      $this->getDatabase()->schema()->createTable($this->messageTableName(), $schema);
+    }
+    else {
+      // Add any missing columns to the map table.
+      if (!$this->getDatabase()->schema()->fieldExists($this->mapTableName,
+                                                    'rollback_action')) {
+        $this->getDatabase()->schema()->addField($this->mapTableName,
+                                              'rollback_action', array(
           'type' => 'int',
           'size' => 'tiny',
           'unsigned' => TRUE,
           'not null' => TRUE,
-          'default' => MigrateIdMapInterface::STATUS_IMPORTED,
-          'description' => 'Indicates current status of the source row',
-        );
-        $fields['rollback_action'] = array(
-          'type' => 'int',
-          'size' => 'tiny',
-          'unsigned' => TRUE,
-          'not null' => TRUE,
-          'default' => MigrateIdMapInterface::ROLLBACK_DELETE,
-          'description' => 'Flag indicating what to do for this item on rollback',
-        );
-        $fields['last_imported'] = array(
-          'type' => 'int',
-          'unsigned' => TRUE,
-          'not null' => TRUE,
           'default' => 0,
-          'description' => 'UNIX timestamp of the last time this row was imported',
-        );
-        $fields['hash'] = array(
+          'description' => 'Flag indicating what to do for this item on rollback',
+        ));
+      }
+      if (!$this->getDatabase()->schema()->fieldExists($this->mapTableName, 'hash')) {
+        $this->getDatabase()->schema()->addField($this->mapTableName, 'hash', array(
           'type' => 'varchar',
           'length' => '64',
           'not null' => FALSE,
           'description' => 'Hash of source row data, for detecting changes',
-        );
-        $schema = array(
-          'description' => 'Mappings from source identifier value(s) to destination identifier value(s).',
-          'fields' => $fields,
-        );
-        if ($pks) {
-          $schema['primary key'] = $pks;
-        }
-        $this->getDatabase()->schema()->createTable($this->mapTableName, $schema);
-
-        // Now do the message table.
-        $fields = array();
-        $fields['msgid'] = array(
-          'type' => 'serial',
-          'unsigned' => TRUE,
-          'not null' => TRUE,
-        );
-        $fields += $source_id_schema;
-
-        $fields['level'] = array(
-          'type' => 'int',
-          'unsigned' => TRUE,
-          'not null' => TRUE,
-          'default' => 1,
-        );
-        $fields['message'] = array(
-          'type' => 'text',
-          'size' => 'medium',
-          'not null' => TRUE,
-        );
-        $schema = array(
-          'description' => 'Messages generated during a migration process',
-          'fields' => $fields,
-          'primary key' => array('msgid'),
-        );
-        if ($pks) {
-          $schema['indexes']['sourcekey'] = $pks;
-        }
-        $this->getDatabase()->schema()->createTable($this->messageTableName, $schema);
+        ));
       }
-      else {
-        // Add any missing columns to the map table.
-        if (!$this->getDatabase()->schema()->fieldExists($this->mapTableName,
-                                                      'rollback_action')) {
-          $this->getDatabase()->schema()->addField($this->mapTableName,
-                                                'rollback_action', array(
-            'type' => 'int',
-            'size' => 'tiny',
-            'unsigned' => TRUE,
-            'not null' => TRUE,
-            'default' => 0,
-            'description' => 'Flag indicating what to do for this item on rollback',
-          ));
-        }
-        if (!$this->getDatabase()->schema()->fieldExists($this->mapTableName, 'hash')) {
-          $this->getDatabase()->schema()->addField($this->mapTableName, 'hash', array(
-            'type' => 'varchar',
-            'length' => '64',
-            'not null' => FALSE,
-            'description' => 'Hash of source row data, for detecting changes',
-          ));
-        }
-      }
-      $this->ensured = TRUE;
     }
   }
 
   /**
+   * Create schema from an id definition.
+   *
+   * @param array $id_definition
+   *   A field schema definition. Can be SQL schema or a type data
+   *   based schema. In the latter case, the value of type needs to be
+   *   $typed_data_type.$column
+   * @return array
+   */
+  protected function getFieldSchema(array $id_definition) {
+    $type_parts = explode('.', $id_definition['type']);
+    if (count($type_parts) == 1) {
+      $type_parts[] = 'value';
+    }
+    $schema = FieldDefinition::create($type_parts[0])->getColumns();
+    return $schema[$type_parts[1]];
+  }
+
+  /**
    * {@inheritdoc}
    */
   public function getRowBySource(array $source_id_values) {
-    $query = $this->getDatabase()->select($this->mapTableName, 'map')
+    $query = $this->getDatabase()->select($this->mapTableName(), 'map')
               ->fields('map');
-    foreach ($this->sourceIdFields as $source_id) {
+    foreach ($this->sourceIdFields() as $source_id) {
       $query = $query->condition("map.$source_id", array_shift($source_id_values), '=');
     }
     $result = $query->execute();
@@ -345,9 +394,9 @@ public function getRowBySource(array $source_id_values) {
    * {@inheritdoc}
    */
   public function getRowByDestination(array $destination_id_values) {
-    $query = $this->getDatabase()->select($this->mapTableName, 'map')
+    $query = $this->getDatabase()->select($this->mapTableName(), 'map')
               ->fields('map');
-    foreach ($this->destinationIdFields as $destination_id) {
+    foreach ($this->destinationIdFields() as $destination_id) {
       $query = $query->condition("map.$destination_id", array_shift($destination_id_values), '=');
     }
     $result = $query->execute();
@@ -359,7 +408,7 @@ public function getRowByDestination(array $destination_id_values) {
    */
   public function getRowsNeedingUpdate($count) {
     $rows = array();
-    $result = $this->getDatabase()->select($this->mapTableName, 'map')
+    $result = $this->getDatabase()->select($this->mapTableName(), 'map')
                       ->fields('map')
                       ->condition('source_row_status', MigrateIdMapInterface::STATUS_NEEDS_UPDATE)
                       ->range(0, $count)
@@ -374,9 +423,9 @@ public function getRowsNeedingUpdate($count) {
    * {@inheritdoc}
    */
   public function lookupSourceID(array $destination_id) {
-    $query = $this->getDatabase()->select($this->mapTableName, 'map')
-              ->fields('map', $this->sourceIdFields);
-    foreach ($this->destinationIdFields as $key_name) {
+    $query = $this->getDatabase()->select($this->mapTableName(), 'map')
+              ->fields('map', $this->sourceIdFields());
+    foreach ($this->destinationIdFields() as $key_name) {
       $query = $query->condition("map.$key_name", array_shift($destination_id), '=');
     }
     $result = $query->execute();
@@ -388,9 +437,12 @@ public function lookupSourceID(array $destination_id) {
    * {@inheritdoc}
    */
   public function lookupDestinationId(array $source_id) {
-    $query = $this->getDatabase()->select($this->mapTableName, 'map')
-              ->fields('map', $this->destinationIdFields);
-    foreach ($this->sourceIdFields as $key_name) {
+    if (empty($source_id)) {
+      return array();
+    }
+    $query = $this->getDatabase()->select($this->mapTableName(), 'map')
+              ->fields('map', $this->destinationIdFields());
+    foreach ($this->sourceIdFields() as $key_name) {
       $query = $query->condition("map.$key_name", array_shift($source_id), '=');
     }
     $result = $query->execute();
@@ -406,12 +458,12 @@ public function saveIdMapping(Row $row, array $destination_id_values, $source_ro
     $source_id_values = $row->getSourceIdValues();
     // Construct the source key and initialize to empty variable keys.
     $keys = array();
-    foreach ($this->sourceIdFields as $field_name => $key_name) {
+    foreach ($this->sourceIdFields() as $field_name => $key_name) {
       // A NULL key value will fail.
       if (!isset($source_id_values[$field_name])) {
         $this->message->display(t(
           'Could not save to map table due to NULL value for key field !field',
-          array('!field' => $field_name)));
+          array('!field' => $field_name)), 'error');
         return;
       }
       $keys[$key_name] = $source_id_values[$field_name];
@@ -422,16 +474,20 @@ public function saveIdMapping(Row $row, array $destination_id_values, $source_ro
       'rollback_action' => (int) $rollback_action,
       'hash' => $row->getHash(),
     );
-    $count = 1;
+    $count = 0;
     foreach ($destination_id_values as $dest_id) {
-      $fields['destid' . $count++] = $dest_id;
+      $fields['destid' . ++$count] = $dest_id;
+    }
+    if ($count && $count != count($this->destinationIdFields())) {
+      $this->message->display(t('Could not save to map table due to missing destination id values'), 'error');
+      return;
     }
     if ($this->migration->get('trackLastImported')) {
       $fields['last_imported'] = time();
     }
     if ($keys) {
-      $this->getDatabase()->merge($this->mapTableName)
-        ->keys($keys)
+      $this->getDatabase()->merge($this->mapTableName())
+        ->key($keys)
         ->fields($fields)
         ->execute();
     }
@@ -451,7 +507,7 @@ public function saveMessage(array $source_id_values, $message, $level = Migratio
     }
     $fields['level'] = $level;
     $fields['message'] = $message;
-    $this->getDatabase()->insert($this->messageTableName)
+    $this->getDatabase()->insert($this->messageTableName())
       ->fields($fields)
       ->execute();
   }
@@ -460,7 +516,7 @@ public function saveMessage(array $source_id_values, $message, $level = Migratio
    * {@inheritdoc}
    */
   public function prepareUpdate() {
-    $this->getDatabase()->update($this->mapTableName)
+    $this->getDatabase()->update($this->mapTableName())
     ->fields(array('source_row_status' => MigrateIdMapInterface::STATUS_NEEDS_UPDATE))
     ->execute();
   }
@@ -469,7 +525,7 @@ public function prepareUpdate() {
    * {@inheritdoc}
    */
   public function processedCount() {
-    return $this->getDatabase()->select($this->mapTableName)
+    return $this->getDatabase()->select($this->mapTableName())
       ->countQuery()
       ->execute()
       ->fetchField();
@@ -479,7 +535,7 @@ public function processedCount() {
    * {@inheritdoc}
    */
   public function importedCount() {
-    return $this->getDatabase()->select($this->mapTableName)
+    return $this->getDatabase()->select($this->mapTableName())
       ->condition('source_row_status', array(MigrateIdMapInterface::STATUS_IMPORTED, MigrateIdMapInterface::STATUS_NEEDS_UPDATE), 'IN')
       ->countQuery()
       ->execute()
@@ -504,7 +560,7 @@ public function errorCount() {
    * {@inheritdoc}
    */
   public function messageCount() {
-    return $this->countHelper(NULL, $this->messageTableName);
+    return $this->countHelper(NULL, $this->messageTableName());
   }
 
   /**
@@ -518,7 +574,7 @@ public function messageCount() {
    *   The number of records.
    */
   protected function countHelper($status, $table = NULL) {
-    $query = $this->getDatabase()->select($table ?: $this->mapTableName);
+    $query = $this->getDatabase()->select($table ?: $this->mapTableName());
     if (isset($status)) {
       $query->condition('source_row_status', $status);
     }
@@ -533,9 +589,9 @@ public function delete(array $source_id_values, $messages_only = FALSE) {
       throw new MigrateException('Without source identifier values it is impossible to find the row to delete.');
     }
     if (!$messages_only) {
-      $map_query = $this->getDatabase()->delete($this->mapTableName);
+      $map_query = $this->getDatabase()->delete($this->mapTableName());
     }
-    $message_query = $this->getDatabase()->delete($this->messageTableName);
+    $message_query = $this->getDatabase()->delete($this->messageTableName());
     $count = 1;
     foreach ($source_id_values as $id_value) {
       if (!$messages_only) {
@@ -555,8 +611,8 @@ public function delete(array $source_id_values, $messages_only = FALSE) {
    * {@inheritdoc}
    */
   public function deleteDestination(array $destination_id) {
-    $map_query = $this->getDatabase()->delete($this->mapTableName);
-    $message_query = $this->getDatabase()->delete($this->messageTableName);
+    $map_query = $this->getDatabase()->delete($this->mapTableName());
+    $message_query = $this->getDatabase()->delete($this->messageTableName());
     $source_id = $this->lookupSourceID($destination_id);
     if (!empty($source_id)) {
       $count = 1;
@@ -582,7 +638,7 @@ public function setUpdate(array $source_id) {
       throw new MigrateException('No source identifiers provided to update.');
     }
     $query = $this->getDatabase()
-      ->update($this->mapTableName)
+      ->update($this->mapTableName())
       ->fields(array('source_row_status' => MigrateIdMapInterface::STATUS_NEEDS_UPDATE));
     $count = 1;
     foreach ($source_id as $key_value) {
@@ -596,22 +652,22 @@ public function setUpdate(array $source_id) {
    */
   public function deleteBulk(array $source_id_values) {
     // If we have a single-column key, we can shortcut it.
-    if (count($this->sourceIds) == 1) {
+    if (count($this->migration->getSourcePlugin()->getIds()) == 1) {
       $sourceids = array();
       foreach ($source_id_values as $source_id) {
         $sourceids[] = $source_id;
       }
-      $this->getDatabase()->delete($this->mapTableName)
+      $this->getDatabase()->delete($this->mapTableName())
         ->condition('sourceid1', $sourceids, 'IN')
         ->execute();
-      $this->getDatabase()->delete($this->messageTableName)
+      $this->getDatabase()->delete($this->messageTableName())
         ->condition('sourceid1', $sourceids, 'IN')
         ->execute();
     }
     else {
       foreach ($source_id_values as $source_id) {
-        $map_query = $this->getDatabase()->delete($this->mapTableName);
-        $message_query = $this->getDatabase()->delete($this->messageTableName);
+        $map_query = $this->getDatabase()->delete($this->mapTableName());
+        $message_query = $this->getDatabase()->delete($this->messageTableName());
         $count = 1;
         foreach ($source_id as $key_value) {
           $map_query->condition('sourceid' . $count, $key_value);
@@ -627,15 +683,15 @@ public function deleteBulk(array $source_id_values) {
    * {@inheritdoc}
    */
   public function clearMessages() {
-    $this->getDatabase()->truncate($this->messageTableName)->execute();
+    $this->getDatabase()->truncate($this->messageTableName())->execute();
   }
 
   /**
    * {@inheritdoc}
    */
   public function destroy() {
-    $this->getDatabase()->schema()->dropTable($this->mapTableName);
-    $this->getDatabase()->schema()->dropTable($this->messageTableName);
+    $this->getDatabase()->schema()->dropTable($this->mapTableName());
+    $this->getDatabase()->schema()->dropTable($this->messageTableName());
   }
 
   /**
@@ -648,10 +704,10 @@ public function destroy() {
   public function rewind() {
     $this->currentRow = NULL;
     $fields = array();
-    foreach ($this->sourceIdFields as $field) {
+    foreach ($this->sourceIdFields() as $field) {
       $fields[] = $field;
     }
-    foreach ($this->destinationIdFields as $field) {
+    foreach ($this->destinationIdFields() as $field) {
       $fields[] = $field;
     }
 
@@ -661,7 +717,7 @@ public function rewind() {
       $query = $query->range(0, $this->options['itemlimit']);
     }
     */
-    $this->result = $this->getDatabase()->select($this->mapTableName, 'map')
+    $this->result = $this->getDatabase()->select($this->mapTableName(), 'map')
       ->fields('map', $fields)
       ->execute();
     $this->next();
@@ -697,7 +753,7 @@ public function next() {
     $this->currentRow = $this->result->fetchAssoc();
     $this->currentKey = array();
     if ($this->currentRow) {
-      foreach ($this->sourceIdFields as $map_field) {
+      foreach ($this->sourceIdFields() as $map_field) {
         $this->currentKey[$map_field] = $this->currentRow[$map_field];
         // Leave only destination fields.
         unset($this->currentRow[$map_field]);
diff --git a/core/modules/migrate/lib/Drupal/migrate/Plugin/migrate/process/Callback.php b/core/modules/migrate/lib/Drupal/migrate/Plugin/migrate/process/Callback.php
new file mode 100644
index 0000000..b1ecd2d
--- /dev/null
+++ b/core/modules/migrate/lib/Drupal/migrate/Plugin/migrate/process/Callback.php
@@ -0,0 +1,39 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\migrate\Plugin\migrate\process\Callback.
+ */
+
+namespace Drupal\migrate\Plugin\migrate\process;
+
+use Drupal\migrate\MigrateExecutable;
+use Drupal\migrate\ProcessPluginBase;
+use Drupal\migrate\Row;
+
+/**
+ * This plugin allows source value to be passed to a callback.
+ *
+ * The current value is passed to a callable that returns the processed value.
+ * This plugin allows simple processing of the value, such as strtolower(). The
+ * callable takes the value as the single mandatory argument. No additional
+ * arguments can be passed to the callback as this would make the migration YAML
+ * file too complex.
+ *
+ * @MigrateProcessPlugin(
+ *   id = "callback"
+ * )
+ */
+class Callback extends ProcessPluginBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function transform($value, MigrateExecutable $migrate_executable, Row $row, $destination_property) {
+    if (is_callable($this->configuration['callable'])) {
+      $value = call_user_func($this->configuration['callable'], $value);
+    }
+    return $value;
+  }
+
+}
diff --git a/core/modules/migrate/lib/Drupal/migrate/Plugin/migrate/process/Concat.php b/core/modules/migrate/lib/Drupal/migrate/Plugin/migrate/process/Concat.php
new file mode 100644
index 0000000..4296057
--- /dev/null
+++ b/core/modules/migrate/lib/Drupal/migrate/Plugin/migrate/process/Concat.php
@@ -0,0 +1,41 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\migrate\Plugin\migrate\process\Concat.
+ */
+
+namespace Drupal\migrate\Plugin\migrate\process;
+
+use Drupal\Component\Utility\String;
+use Drupal\migrate\MigrateException;
+use Drupal\migrate\MigrateExecutable;
+use Drupal\migrate\ProcessPluginBase;
+use Drupal\migrate\Row;
+
+/**
+ * Concatenates the strings in the current value.
+ *
+ * @MigrateProcessPlugin(
+ *   id = "concat",
+ *   handle_multiples = TRUE
+ * )
+ */
+class Concat extends ProcessPluginBase {
+
+  /**
+   * {@inheritdoc}
+   *
+   * Concatenates the strings in the current value.
+   */
+  public function transform($value, MigrateExecutable $migrate_executable, Row $row, $destination_property) {
+    if (is_array($value)) {
+      $delimiter = isset($this->configuration['delimiter']) ? $this->configuration['delimiter'] : '';
+      return implode($delimiter, $value);
+    }
+    else {
+      throw new MigrateException(sprintf('%s is not an array', String::checkPlain(var_export($value, TRUE))));
+    }
+  }
+
+}
diff --git a/core/modules/migrate/lib/Drupal/migrate/Plugin/migrate/process/DefaultValue.php b/core/modules/migrate/lib/Drupal/migrate/Plugin/migrate/process/DefaultValue.php
index fb4aea0..d129bd9 100644
--- a/core/modules/migrate/lib/Drupal/migrate/Plugin/migrate/process/DefaultValue.php
+++ b/core/modules/migrate/lib/Drupal/migrate/Plugin/migrate/process/DefaultValue.php
@@ -25,6 +25,9 @@ class DefaultValue extends ProcessPluginBase {
    * {@inheritdoc}
    */
   public function transform($value, MigrateExecutable $migrate_executable, Row $row, $destination_property) {
-    return isset($value) ? $value : $this->configuration['default_value'];
+    if (!empty($this->configuration['strict'])) {
+      return isset($value) ? $value : $this->configuration['default_value'];
+    }
+    return $value ?: $this->configuration['default_value'];
   }
 }
diff --git a/core/modules/migrate/lib/Drupal/migrate/Plugin/migrate/process/Migration.php b/core/modules/migrate/lib/Drupal/migrate/Plugin/migrate/process/Migration.php
new file mode 100644
index 0000000..0a8e352
--- /dev/null
+++ b/core/modules/migrate/lib/Drupal/migrate/Plugin/migrate/process/Migration.php
@@ -0,0 +1,137 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\migrate\Plugin\migrate\process\Migration.
+ */
+
+
+namespace Drupal\migrate\Plugin\migrate\process;
+
+use Drupal\Core\Entity\EntityStorageControllerInterface;
+use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
+use Drupal\migrate\MigrateException;
+use Drupal\migrate\Plugin\MigratePluginManager;
+use Drupal\migrate\ProcessPluginBase;
+use Drupal\migrate\Entity\MigrationInterface;
+use Drupal\migrate\MigrateExecutable;
+use Drupal\migrate\Row;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+
+/**
+ * Calculates the value of a property based on a previous migration.
+ *
+ * @MigrateProcessPlugin(
+ *   id = "migration"
+ * )
+ */
+class Migration extends ProcessPluginBase implements  ContainerFactoryPluginInterface {
+
+  /**
+   * @var \Drupal\migrate\Plugin\MigratePluginManager
+   */
+  protected $processPluginManager;
+
+  /**
+   * @var \Drupal\Core\Entity\EntityStorageControllerInterface
+   */
+  protected $migrationStorageController;
+
+  /**
+   * {@inheritdoc}
+   */
+  public function __construct(array $configuration, $plugin_id, array $plugin_definition, MigrationInterface $migration, EntityStorageControllerInterface $storage_controller, MigratePluginManager $process_plugin_manager) {
+    parent::__construct($configuration, $plugin_id, $plugin_definition);
+    $this->migrationStorageController = $storage_controller;
+    $this->migration = $migration;
+    $this->processPluginManager = $process_plugin_manager;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function create(ContainerInterface $container, array $configuration, $plugin_id, array $plugin_definition, MigrationInterface $migration = NULL) {
+    return new static(
+      $configuration,
+      $plugin_id,
+      $plugin_definition,
+      $migration,
+      $container->get('entity.manager')->getStorageController('migration'),
+      $container->get('plugin.manager.migrate.process')
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function transform($value, MigrateExecutable $migrate_executable, Row $row, $destination_property) {
+    $migration_ids = $this->configuration['migration'];
+    if (!is_array($migration_ids)) {
+      $migration_ids = array($migration_ids);
+    }
+    $scalar = FALSE;
+    if (!is_array($value)) {
+      $scalar = TRUE;
+      $value = array($value);
+    }
+    $self = FALSE;
+    /** @var \Drupal\migrate\Entity\MigrationInterface[] $migrations */
+    $migrations = $this->migrationStorageController->loadMultiple($migration_ids);
+    $destination_ids = NULL;
+    $source_id_values = array();
+    foreach ($migrations as $migration_id => $migration) {
+      if ($migration_id == $this->migration->id()) {
+        $self = TRUE;
+      }
+      if (isset($this->configuration['source_ids'][$migration_id])) {
+        $configuration = array('source' => $this->configuration['source_ids'][$migration_id]);
+        $source_id_values[$migration_id] = $this->processPluginManager
+          ->createInstance('get', $configuration, $this->migration)
+          ->transform(NULL, $migrate_executable, $row, $destination_property);
+      }
+      else {
+        $source_id_values[$migration_id] = $value;
+      }
+      // Break out of the loop as soon as a destination ID is found.
+      if ($destination_ids = $migration->getIdMap()->lookupDestinationID($source_id_values[$migration_id])) {
+        break;
+      }
+    }
+    if (!$destination_ids && (($self && empty($this->configuration['no stub'])) || isset($this->configuration['stub_id']) || count($migrations) == 1))  {
+      // If the lookup didn't succeed, figure out which migration will do the
+      // stubbing.
+      if ($self) {
+        $migration = $this->migration;
+      }
+      elseif (isset($this->configuration['stub_id'])) {
+        $migration = $migrations[$this->configuration['stub_id']];
+      }
+      else {
+        $migration = reset($migrations);
+      }
+      $destination_plugin = $migration->getDestinationPlugin();
+      // Only keep the process necessary to produce the destination ID.
+      $process = array_intersect_key($migration->get('process'), $destination_plugin->getIds());
+      // We already have the source id values but need to key them for the Row
+      // constructor.
+      $source_ids = $migration->getSourcePlugin()->getIds();
+      $values = array();
+      foreach (array_keys($source_ids) as $index => $source_id) {
+        $values[$source_id] = $source_id_values[$migration->id()][$index];
+      }
+      $stub_row = new Row($values, $source_ids);
+      $stub_row->stub(TRUE);
+      // Do a normal migration with the stub row.
+      $migrate_executable->processRow($stub_row, $process);
+      $destination_ids = $destination_plugin->import($stub_row);
+    }
+    if ($scalar) {
+      if (count($destination_ids) == 1) {
+        return reset($destination_ids);
+      }
+      throw new MigrateException('Migration process plugin failed.');
+    }
+    return $destination_ids;
+  }
+
+}
diff --git a/core/modules/migrate/lib/Drupal/migrate/Plugin/migrate/process/SkipProcessOnEmpty.php b/core/modules/migrate/lib/Drupal/migrate/Plugin/migrate/process/SkipProcessOnEmpty.php
new file mode 100644
index 0000000..bb24bf2
--- /dev/null
+++ b/core/modules/migrate/lib/Drupal/migrate/Plugin/migrate/process/SkipProcessOnEmpty.php
@@ -0,0 +1,36 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\migrate\Plugin\migrate\Process\d6\FlagSkipProcess.
+ */
+
+namespace Drupal\migrate\Plugin\migrate\process;
+
+use Drupal\migrate\MigrateExecutable;
+use Drupal\migrate\MigrateSkipProcessException;
+use Drupal\migrate\ProcessPluginBase;
+use Drupal\migrate\Row;
+
+/**
+ * If the value evaluates to false, skip further processing.
+ *
+ * @MigrateProcessPlugin(
+ *   id = "skip_process_on_empty"
+ * )
+ */
+class SkipProcessOnEmpty extends ProcessPluginBase {
+
+  /**
+   * {@inheritdoc}
+   *
+   * Skip the rest of the processing on 0.
+   */
+  public function transform($value, MigrateExecutable $migrate_executable, Row $row, $destination_property) {
+    if (!$value) {
+      throw new MigrateSkipProcessException();
+    }
+    return $value;
+  }
+
+}
diff --git a/core/modules/migrate/lib/Drupal/migrate/Plugin/migrate/process/SkipRowOnEmpty.php b/core/modules/migrate/lib/Drupal/migrate/Plugin/migrate/process/SkipRowOnEmpty.php
new file mode 100644
index 0000000..156dd33
--- /dev/null
+++ b/core/modules/migrate/lib/Drupal/migrate/Plugin/migrate/process/SkipRowOnEmpty.php
@@ -0,0 +1,34 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\migrate_drupal\Plugin\migrate\process\d6\FlagSkippingRow.
+ */
+
+namespace Drupal\migrate\Plugin\migrate\process;
+
+use Drupal\migrate\ProcessPluginBase;
+use Drupal\migrate\MigrateExecutable;
+use Drupal\migrate\Row;
+use Drupal\migrate\MigrateSkipRowException;
+
+/**
+ * If the source evaluates to empty, we skip the current row.
+ *
+ * @MigrateProcessPlugin(
+ *   id = "skip_row_on_empty"
+ * )
+ */
+class SkipRowOnEmpty extends ProcessPluginBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function transform($value, MigrateExecutable $migrate_executable, Row $row, $destination_property) {
+    if (!$value) {
+      throw new MigrateSkipRowException();
+    }
+    return $value;
+  }
+
+}
diff --git a/core/modules/migrate/lib/Drupal/migrate/Plugin/migrate/process/StaticMap.php b/core/modules/migrate/lib/Drupal/migrate/Plugin/migrate/process/StaticMap.php
index e0f2d95..455cb51 100644
--- a/core/modules/migrate/lib/Drupal/migrate/Plugin/migrate/process/StaticMap.php
+++ b/core/modules/migrate/lib/Drupal/migrate/Plugin/migrate/process/StaticMap.php
@@ -39,8 +39,14 @@ public function transform($value, MigrateExecutable $migrate_executable, Row $ro
     }
     $new_value = NestedArray::getValue($this->configuration['map'], $new_value, $key_exists);
     if (!$key_exists) {
+      if (isset($this->configuration['default_value'])) {
+        if (!empty($this->configuration['bypass'])) {
+          throw new MigrateException('Setting both default_value and bypass is invalid.');
+        }
+        return $this->configuration['default_value'];
+      }
       if (empty($this->configuration['bypass'])) {
-        throw new MigrateException('Lookup failed.');
+        throw new MigrateException(sprintf('Lookup of %s failed.', var_export($value, TRUE)));
       }
       else {
         return $value;
diff --git a/core/modules/migrate/lib/Drupal/migrate/Plugin/migrate/source/EmptySource.php b/core/modules/migrate/lib/Drupal/migrate/Plugin/migrate/source/EmptySource.php
new file mode 100644
index 0000000..acd2067
--- /dev/null
+++ b/core/modules/migrate/lib/Drupal/migrate/Plugin/migrate/source/EmptySource.php
@@ -0,0 +1,53 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\migrate\Plugin\migrate\source\Constants.
+ */
+
+namespace Drupal\migrate\Plugin\migrate\source;
+
+/**
+ * Source returning an empty row.
+ *
+ * This is generally useful when needing to create a field using a migration..
+ *
+ * @MigrateSource(
+ *   id = "empty"
+ * )
+ */
+class EmptySource extends SourcePluginBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function fields() {
+    return array(
+      'id' => t('ID'),
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getIterator() {
+    return new \ArrayIterator(array(array('id' => '')));
+  }
+
+  public function __toString() {
+    return '';
+  }
+
+  public function getIds() {
+    $ids['id']['type'] = 'string';
+    return $ids;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function count() {
+    return 1;
+  }
+
+}
diff --git a/core/modules/migrate/lib/Drupal/migrate/Plugin/migrate/source/SourcePluginBase.php b/core/modules/migrate/lib/Drupal/migrate/Plugin/migrate/source/SourcePluginBase.php
index 0efc013..7b1c92f 100644
--- a/core/modules/migrate/lib/Drupal/migrate/Plugin/migrate/source/SourcePluginBase.php
+++ b/core/modules/migrate/lib/Drupal/migrate/Plugin/migrate/source/SourcePluginBase.php
@@ -12,6 +12,9 @@
 use Drupal\migrate\Plugin\MigrateSourceInterface;
 use Drupal\migrate\Row;
 
+/**
+ * The base class for all source plugins.
+ */
 abstract class SourcePluginBase extends PluginBase implements MigrateSourceInterface  {
 
   /**
@@ -27,7 +30,7 @@
   /**
    * {@inheritdoc}
    */
-  function __construct(array $configuration, $plugin_id, array $plugin_definition, MigrationInterface $migration) {
+  public function __construct(array $configuration, $plugin_id, array $plugin_definition, MigrationInterface $migration) {
     parent::__construct($configuration, $plugin_id, $plugin_definition);
     $this->migration = $migration;
   }
@@ -46,9 +49,12 @@ protected function getModuleHandler() {
    * {@inheritdoc}
    */
   public function prepareRow(Row $row) {
-    $this->getModuleHandler()->invokeAll('migrate_prepare_row', array($row, $this, $this->migration));
-    $this->getModuleHandler()->invokeAll('migrate_ '. $this->migration->id() . '_prepare_row', array($row, $this, $this->migration));
-    return TRUE;
+    $resultHook = $this->getModuleHandler()->invokeAll('migrate_prepare_row', array($row, $this, $this->migration));
+    $resultNamedHook = $this->getModuleHandler()->invokeAll('migrate_'. $this->migration->id() . '_prepare_row', array($row, $this, $this->migration));
+    // If any of the hooks returned false, we want to skip the row.
+    if (($resultHook && in_array(FALSE, $resultHook)) || ($resultNamedHook && in_array(FALSE, $resultNamedHook))) {
+      return FALSE;
+    }
   }
 
 }
diff --git a/core/modules/migrate/lib/Drupal/migrate/Plugin/migrate/source/SqlBase.php b/core/modules/migrate/lib/Drupal/migrate/Plugin/migrate/source/SqlBase.php
index 8740f11..d6d2b97 100644
--- a/core/modules/migrate/lib/Drupal/migrate/Plugin/migrate/source/SqlBase.php
+++ b/core/modules/migrate/lib/Drupal/migrate/Plugin/migrate/source/SqlBase.php
@@ -34,15 +34,14 @@
   /**
    * {@inheritdoc}
    */
-  function __construct(array $configuration, $plugin_id, array $plugin_definition, MigrationInterface $migration) {
+  public function __construct(array $configuration, $plugin_id, array $plugin_definition, MigrationInterface $migration) {
     parent::__construct($configuration, $plugin_id, $plugin_definition, $migration);
-    $this->mapJoinable = TRUE;
   }
 
   /**
    * @return \Drupal\Core\Database\Connection
    */
-  function __toString() {
+  public function __toString() {
     return (string) $this->query;
   }
 
@@ -50,50 +49,48 @@ function __toString() {
    * @return \Drupal\Core\Database\Connection
    */
   public function getDatabase() {
-    if  (!isset($this->database)) {
-      $this->database = static::getDatabaseConnection($this->migration->id(), $this->configuration);
+    if (!isset($this->database)) {
+      $this->database = Database::getConnection('default', 'migrate');
     }
     return $this->database;
   }
 
-  public static function getDatabaseConnection($id, array $configuration) {
-    if (isset($configuration['database'])) {
-      $key = 'migrate_' . $id;
-      Database::addConnectionInfo($key, 'default', $configuration['database']);
-    }
-    else {
-      $key = 'default';
-    }
-    return Database::getConnection('default', $key);
-  }
-
+  /**
+   * Wrapper for database select.
+   */
   protected function select($table, $alias = NULL, array $options = array()) {
     $options['fetch'] = \PDO::FETCH_ASSOC;
     return $this->getDatabase()->select($table, $alias, $options);
   }
 
   /**
+   * A helper for adding tags and metadata to the query.
+   *
+   * @return \Drupal\Core\Database\Query\SelectInterface
+   *   The query with additional tags and metadata.
+   */
+  protected function prepareQuery() {
+    $this->query = clone $this->query();
+    $this->query->addTag('migrate');
+    $this->query->addTag('migrate_' . $this->migration->id());
+    $this->query->addMetaData('migration', $this->migration);
+
+    return $this->query;
+  }
+
+  /**
    * Implementation of MigrateSource::performRewind().
    *
    * We could simply execute the query and be functionally correct, but
    * we will take advantage of the PDO-based API to optimize the query up-front.
    */
   protected function runQuery() {
-    $this->query = clone $this->query();
-    $this->query->addTag('migrate');
-    $this->query->addTag('migrate_' . $this->migration->id());
-    $this->query->addMetaData('migration', $this->migration);
+    $this->prepareQuery();
     $highwaterProperty = $this->migration->get('highwaterProperty');
 
     // Get the key values, for potential use in joining to the map table, or
     // enforcing idlist.
     $keys = array();
-    foreach ($this->migration->get('sourceIds') as $field_name => $field_schema) {
-      if (isset($field_schema['alias'])) {
-        $field_name = $field_schema['alias'] . '.' . $field_name;
-      }
-      $keys[] = $field_name;
-    }
 
     // The rules for determining what conditions to add to the query are as
     // follows (applying first applicable rule)
@@ -113,13 +110,13 @@ protected function runQuery() {
       //      OR above highwater).
       $conditions = $this->query->orConditionGroup();
       $condition_added = FALSE;
-      if ($this->mapJoinable) {
+      if ($this->getIds() && ($this->migration->getIdMap() instanceof \Drupal\migrate\Plugin\migrate\id_map\Sql)) {
         // Build the join to the map table. Because the source key could have
         // multiple fields, we need to build things up.
         $count = 1;
         $map_join = '';
         $delimiter = '';
-        foreach ($this->migration->get('sourceIds') as $field_name => $field_schema) {
+        foreach ($this->getIds() as $field_name => $field_schema) {
           if (isset($field_schema['alias'])) {
             $field_name = $field_schema['alias'] . '.' . $field_name;
           }
@@ -133,7 +130,7 @@ protected function runQuery() {
         $condition_added = TRUE;
 
         // And as long as we have the map table, add its data to the row.
-        $n = count($this->migration->get('sourceIds'));
+        $n = count($this->getIds());
         for ($count = 1; $count <= $n; $count++) {
           $map_key = 'sourceid' . $count;
           $this->query->addField($alias, $map_key, "migrate_map_$map_key");
@@ -168,7 +165,7 @@ protected function runQuery() {
   /**
    * @return \Drupal\Core\Database\Query\SelectInterface
    */
-  abstract function query();
+  abstract public function query();
 
   /**
    * {@inheritdoc}
diff --git a/core/modules/migrate/lib/Drupal/migrate/Plugin/migrate/source/d7/Node.php b/core/modules/migrate/lib/Drupal/migrate/Plugin/migrate/source/d7/Node.php
new file mode 100644
index 0000000..9791f61
--- /dev/null
+++ b/core/modules/migrate/lib/Drupal/migrate/Plugin/migrate/source/d7/Node.php
@@ -0,0 +1,66 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\migrate\Plugin\migrate\source\d7\Node.
+ */
+
+namespace Drupal\migrate\Plugin\migrate\source\d7;
+
+use Drupal\migrate\Plugin\migrate\source\SqlBase;
+
+/**
+ * Drupal 7 node source.
+ *
+ * @PluginID("drupal7_node")
+ */
+class Node extends SqlBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function query() {
+    return $this->database->select('node', 'n')
+     ->fields('n', array('nid', 'vid', 'language', 'title', 'uid',
+       'status', 'created', 'changed', 'comment', 'promote', 'sticky',
+       'tnid', 'translate'))
+     ->condition('n.type', $this->sourceType)
+     ->orderBy('n.changed');
+
+  }
+
+  public function getCurrentKey() {
+    // TODO: Implement getCurrentKey() method.
+  }
+
+  public function fields() {
+    // TODO: Implement fields() method.
+  }
+
+  public function getIgnored() {
+    // TODO: Implement getIgnored() method.
+  }
+
+  public function getProcessed() {
+    // TODO: Implement getProcessed() method.
+  }
+
+  public function resetStats() {
+    // TODO: Implement resetStats() method.
+  }
+
+  /**
+   * (PHP 5 &gt;= 5.1.0)<br/>
+   * Count elements of an object
+   * @link http://php.net/manual/en/countable.count.php
+   * @return int The custom count as an integer.
+   * </p>
+   * <p>
+   * The return value is cast to an integer.
+   */
+  public function count() {
+    // TODO: Implement count() method.
+  }
+
+
+}
diff --git a/core/modules/migrate/lib/Drupal/migrate/Row.php b/core/modules/migrate/lib/Drupal/migrate/Row.php
index 2a29f61..342b706 100644
--- a/core/modules/migrate/lib/Drupal/migrate/Row.php
+++ b/core/modules/migrate/lib/Drupal/migrate/Row.php
@@ -57,6 +57,27 @@ class Row {
   protected $frozen = FALSE;
 
   /**
+   * The raw destination properties.
+   *
+   * Unlike $destination which is set by using
+   * \Drupal\Component\Utility\NestedArray::setValue() this array contains
+   * the destination as setDestinationProperty was called.
+   *
+   * @var array
+   *   The raw destination.
+   *
+   * @see getRawDestination()
+   */
+  protected $rawDestination;
+
+  /**
+   * TRUE when this row is a stub.
+   *
+   * @var bool
+   */
+  protected $stub = FALSE;
+
+  /**
    * Constructs a \Drupal\Migrate\Row object.
    *
    * @param array $values
@@ -98,7 +119,7 @@ public function getSourceIdValues() {
    *   TRUE if the source has property; FALSE otherwise.
    */
   public function hasSourceProperty($property) {
-    return isset($this->source[$property]) || array_key_exists($property, $this->source);
+    return NestedArray::keyExists($this->source, explode('.', $property));
   }
 
   /**
@@ -111,8 +132,9 @@ public function hasSourceProperty($property) {
    *   The found returned property or NULL if not found.
    */
   public function getSourceProperty($property) {
-    if (isset($this->source[$property])) {
-      return $this->source[$property];
+    $return = NestedArray::getValue($this->source, explode('.', $property), $key_exists);
+    if ($key_exists) {
+      return $return;
     }
   }
 
@@ -143,7 +165,7 @@ public function setSourceProperty($property, $data) {
       throw new \Exception("The source is frozen and can't be changed any more");
     }
     else {
-      $this->source[$property] = $data;
+      NestedArray::setValue($this->source, explode('.', $property), $data, TRUE);
     }
   }
 
@@ -164,7 +186,7 @@ public function freezeSource() {
    *   TRUE if the destination property exists.
    */
   public function hasDestinationProperty($property) {
-    return NestedArray::keyExists($this->destination, explode(':', $property));
+    return NestedArray::keyExists($this->destination, explode('.', $property));
   }
 
   /**
@@ -176,7 +198,8 @@ public function hasDestinationProperty($property) {
    *   The property value to set on the destination.
    */
   public function setDestinationProperty($property, $value) {
-    NestedArray::setValue($this->destination, explode(':', $property), $value, TRUE);
+    $this->rawDestination[$property] = $value;
+    NestedArray::setValue($this->destination, explode('.', $property), $value, TRUE);
   }
 
   /**
@@ -190,16 +213,31 @@ public function getDestination() {
   }
 
   /**
+   * Returns the raw destination. Rarely necessary.
+   *
+   * For example calling setDestination('foo:bar', 'baz') results in
+   * @code
+   * $this->destination['foo']['bar'] = 'baz';
+   * $this->rawDestination['foo.bar'] = 'baz';
+   *
+   * @return array
+   *   The raw destination values.
+   */
+  public function getRawDestination() {
+    return $this->rawDestination;
+  }
+
+  /**
    * Returns the value of a destination property.
    *
-   * @param array|string $property
-   *   An array of properties on the destination.
+   * @param string $property
+   *   The name of a property on the destination.
    *
    * @return mixed
    *  The destination value.
    */
   public function getDestinationProperty($property) {
-    return NestedArray::getValue($this->destination, explode(':', $property));
+    return NestedArray::getValue($this->destination, explode('.', $property));
   }
 
   /**
@@ -261,4 +299,20 @@ public function getHash() {
     return $this->idMap['hash'];
   }
 
+  /**
+   * Flags and reports this row as a stub.
+   *
+   * @param bool|null $new_value
+   *   TRUE when the row is a stub. Omit to determine whether the row is a
+   *   stub.
+   *
+   * @return mixed
+   *   The current stub value.
+   */
+  public function stub($new_value = NULL) {
+    if (isset($new_value)) {
+      $this->stub = $new_value;
+    }
+    return $this->stub;
+  }
 }
diff --git a/core/modules/migrate/lib/Drupal/migrate/Source.php b/core/modules/migrate/lib/Drupal/migrate/Source.php
index ebec104..629873f 100644
--- a/core/modules/migrate/lib/Drupal/migrate/Source.php
+++ b/core/modules/migrate/lib/Drupal/migrate/Source.php
@@ -121,14 +121,23 @@ class Source implements \Iterator, \Countable {
    */
   protected $highwaterProperty;
 
+  /**
+   * Getter for currentIds data member.
+   */
   public function getCurrentIds() {
     return $this->currentIds;
   }
 
+  /**
+   * Getter for numIgnored data member.
+   */
   public function getIgnored() {
     return $this->numIgnored;
   }
 
+  /**
+   * Getter for numProcessed data member.
+   */
   public function getProcessed() {
     return $this->numProcessed;
   }
@@ -141,11 +150,16 @@ public function resetStats() {
   }
 
   /**
+   * Get the source count.
+   *
    * Return a count of available source records, from the cache if appropriate.
    * Returns -1 if the source is not countable.
    *
-   * @param boolean $refresh
+   * @param bool $refresh
+   *   Whether or not to refresh the count.
+   *
    * @return int
+   *   The count.
    */
   public function count($refresh = FALSE) {
     if ($this->skipCount) {
@@ -167,12 +181,12 @@ public function count($refresh = FALSE) {
       // Caching is in play, first try to retrieve a cached count.
       $cache_object = $this->cache->get($this->cacheKey, 'cache');
       if (is_object($cache_object)) {
-        // Success
+        // Success.
         $count = $cache_object->data;
       }
       else {
         // No cached count, ask the derived class to count 'em up, and cache
-        // the result
+        // the result.
         $count = $source->count();
         $this->cache->set($this->cacheKey, $count, 'cache');
       }
@@ -184,9 +198,11 @@ public function count($refresh = FALSE) {
    * Class constructor.
    *
    * @param \Drupal\migrate\Entity\MigrationInterface $migration
+   *   The migration entity.
    * @param \Drupal\migrate\MigrateExecutable $migrate_executable
+   *   The migration executable.
    */
-  function __construct(MigrationInterface $migration, MigrateExecutable $migrate_executable) {
+  public function __construct(MigrationInterface $migration, MigrateExecutable $migrate_executable) {
     $this->migration = $migration;
     $this->migrateExecutable = $migrate_executable;
     $configuration = $migration->get('source');
@@ -205,7 +221,10 @@ function __construct(MigrationInterface $migration, MigrateExecutable $migrate_e
   }
 
   /**
+   * Get the cache object.
+   *
    * @return \Drupal\Core\Cache\CacheBackendInterface
+   *   The cache object.
    */
   protected function getCache() {
     if (!isset($this->cache)) {
@@ -215,7 +234,10 @@ protected function getCache() {
   }
 
   /**
+   * Get the source iterator.
+   *
    * @return \Iterator
+   *   The source iterator.
    */
   protected function getIterator() {
     if (!isset($this->iterator)) {
@@ -232,23 +254,30 @@ public function current() {
   }
 
   /**
-   * Implementation of Iterator::key - called when entering a loop iteration, returning
-   * the key of the current row. It must be a scalar - we will serialize
-   * to fulfill the requirement, but using getCurrentIds() is preferable.
+   * Get the iterator key.
+   *
+   * Implementation of Iterator::key - called when entering a loop iteration,
+   * returning the key of the current row. It must be a scalar - we will
+   * serialize to fulfill the requirement, but using getCurrentIds() is
+   * preferable.
    */
   public function key() {
     return serialize($this->currentIds);
   }
 
   /**
-   * Implementation of Iterator::valid() - called at the top of the loop, returning
-   * TRUE to process the loop and FALSE to terminate it
+   * Whether the iterator is currently valid.
+   *
+   * Implementation of Iterator::valid() - called at the top of the loop,
+   * returning TRUE to process the loop and FALSE to terminate it
    */
   public function valid() {
     return isset($this->currentRow);
   }
 
   /**
+   * Rewind the iterator.
+   *
    * Implementation of Iterator::rewind() - subclasses of MigrateSource should
    * implement performRewind() to do any class-specific setup for iterating
    * source records.
@@ -272,13 +301,14 @@ public function rewind() {
   public function next() {
     $this->currentIds = NULL;
     $this->currentRow = NULL;
+    $source_configuration = $this->migration->get('source');
 
     while ($this->getIterator()->valid()) {
-      $row_data = $this->getIterator()->current();
+      $row_data = $this->getIterator()->current() + $source_configuration;
       $this->getIterator()->next();
-      $row = new Row($row_data, $this->migration->get('sourceIds'), $this->migration->get('destinationIds'));
+      $row = new Row($row_data, $this->migration->getSourcePlugin()->getIds(), $this->migration->get('destinationIds'));
 
-      // Populate the source key for this row
+      // Populate the source key for this row.
       $this->currentIds = $row->getSourceIdValues();
 
       // Pick up the existing map row, if any, unless getNextRow() did it.
@@ -307,7 +337,7 @@ public function next() {
       }
       // 3. If the row is marked as needing update, pass it.
       elseif ($row->needsUpdate()) {
-        // Fall through
+        // Fall through.
       }
       // 4. At this point, we have a row which has previously been imported and
       //    not marked for update. If we're not using highwater marks, then we
@@ -346,22 +376,22 @@ public function next() {
       // 6. So, we are using highwater marks. Take the row if its highwater
       //    field value is greater than the saved mark, otherwise skip it.
       else {
-        // Call prepareRow() here, in case the highwaterField needs preparation
+        // Call prepareRow() here, in case the highwaterField needs preparation.
         if ($this->prepareRow($row) !== FALSE) {
           if ($row->getSourceProperty($this->highwaterProperty['name']) > $this->originalHighwater) {
             $this->currentRow = $row;
             break;
           }
           else {
-            // Skip
+            // Skip.
             continue;
           }
         }
         $prepared = TRUE;
       }
 
-      // Allow the Migration to prepare this row. prepareRow() can return boolean
-      // FALSE to ignore this row.
+      // Allow the Migration to prepare this row. prepareRow() can return
+      // boolean FALSE to ignore this row.
       if (!$prepared) {
         if ($this->prepareRow($row) !== FALSE) {
           // Finally, we've got a keeper.
@@ -385,10 +415,14 @@ public function next() {
    * Source classes should override this as necessary and manipulate $keep.
    *
    * @param \Drupal\migrate\Row $row
+   *   The row object.
+   *
+   * @return bool
+   *   TRUE if we're to process the row otherwise FALSE.
    */
   protected function prepareRow(Row $row) {
-    // We're explicitly skipping this row - keep track in the map table
-    if ($this->migration->getSourcePlugin()->prepareRow($row) === FALSE) {
+    // We're explicitly skipping this row - keep track in the map table.
+    if (($result = $this->migration->getSourcePlugin()->prepareRow($row)) === FALSE) {
       // Make sure we replace any previous messages for this item with any
       // new ones.
       $id_map = $this->migration->getIdMap();
@@ -409,5 +443,7 @@ protected function prepareRow(Row $row) {
       }
     }
     $this->numProcessed++;
+    return $result;
   }
+
 }
diff --git a/core/modules/migrate/lib/Drupal/migrate/Tests/MigrateTestBase.php b/core/modules/migrate/lib/Drupal/migrate/Tests/MigrateTestBase.php
index b8a5e52..f10320b 100644
--- a/core/modules/migrate/lib/Drupal/migrate/Tests/MigrateTestBase.php
+++ b/core/modules/migrate/lib/Drupal/migrate/Tests/MigrateTestBase.php
@@ -9,10 +9,11 @@
 
 use Drupal\Core\Database\Database;
 use Drupal\migrate\Entity\MigrationInterface;
-use Drupal\migrate\Plugin\migrate\source\SqlBase;
+use Drupal\migrate\MigrateMessageInterface;
+use Drupal\migrate\Row;
 use Drupal\simpletest\WebTestBase;
 
-class MigrateTestBase extends WebTestBase {
+class MigrateTestBase extends WebTestBase implements MigrateMessageInterface {
 
   /**
    * The file path(s) to the dumped database(s) to load into the child site.
@@ -21,29 +22,67 @@ class MigrateTestBase extends WebTestBase {
    */
   public $databaseDumpFiles = array();
 
+
+  /**
+   * TRUE to collect messages instead of displaying them.
+   *
+   * @var bool
+   */
+  protected $collectMessages = FALSE;
+
+  /**
+   * A two dimensional array of messages.
+   *
+   * The first key is the type of message, the second is just numeric. Values
+   * are the messages.
+   *
+   * @var array
+   */
+  protected $migrateMessages;
+
   public static $modules = array('migrate');
 
   /**
+   * {@inheritdoc}
+   */
+  protected function setUp() {
+    parent::setUp();
+    $connection_info = Database::getConnectionInfo('default');
+    foreach ($connection_info as $target => $value) {
+      $connection_info[$target]['prefix'] = array(
+        // Simpletest uses 7 character prefixes at most so this can't cause
+        // collisions.
+        'default' => $value['prefix']['default'] .'0',
+      );
+    }
+    Database::addConnectionInfo('migrate', 'default', $connection_info['default']);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function tearDown() {
+    Database::removeConnection('migrate');
+    parent::tearDown();
+  }
+
+  /**
    * @param MigrationInterface $migration
    * @param array $files
    *
    * @return \Drupal\Core\Database\Connection
    */
   protected function prepare(MigrationInterface $migration, array $files = array()) {
-    $databasePrefix = 'm_';
-    $connection_info = Database::getConnectionInfo('default');
-    foreach ($connection_info as $target => $value) {
-      $connection_info[$target]['prefix'] = array(
-        'default' => $value['prefix']['default'] . $databasePrefix,
-      );
-    }
-    $database = SqlBase::getDatabaseConnection($migration->id(), array('database' => $connection_info['default']));
-    foreach (array('source', 'destination', 'idMap') as $key) {
-      $configuration = $migration->get($key);
-      $configuration['database'] = $database;
-      $migration->set($key, $configuration);
-    }
+    $this->loadDumps($files);
+  }
 
+  /**
+   * Load Drupal 6 database dumps to be used.
+   *
+   * @param string $method
+   *   The name of the method in the dump class to use. Defaults to load.
+   */
+  protected function loadDumps($files, $method = 'load') {
     // Load the database from the portable PHP dump.
     // The files may be gzipped.
     foreach ($files as $file) {
@@ -53,8 +92,56 @@ protected function prepare(MigrationInterface $migration, array $files = array()
       }
       preg_match('/^namespace (.*);$/m', file_get_contents($file), $matches);
       $class = $matches[1] . '\\' . basename($file, '.php');
-      $class::load($database);
+      (new $class(Database::getConnection('default', 'migrate')))->$method();
     }
-    return $database;
   }
+
+  /**
+   * @param array $id_mappings
+   *   A list of id mappings keyed by migration ids. Each id mapping is a list
+   *   of two arrays, the first are source ids and the second are destination
+   *   ids.
+   */
+  protected function prepareIdMappings(array $id_mappings) {
+    /** @var \Drupal\migrate\Entity\MigrationInterface[] $migrations */
+    $migrations = entity_load_multiple('migration', array_keys($id_mappings));
+    foreach ($id_mappings as $migration_id => $data) {
+      $migration = $migrations[$migration_id];
+      $id_map = $migration->getIdMap();
+      $id_map->setMessage($this);
+      $source_ids = $migration->getSourcePlugin()->getIds();
+      foreach ($data as $id_mapping) {
+        $row = new Row(array_combine(array_keys($source_ids), $id_mapping[0]), $source_ids);
+        $id_map->saveIdMapping($row, $id_mapping[1]);
+      }
+    }
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function display($message, $type = 'status') {
+    if ($this->collectMessages) {
+      $this->migrateMessages[$type][] = $message;
+    }
+    else {
+      $this->assert($type == 'status', $message, 'migrate');
+    }
+  }
+
+  /**
+   * Start collecting messages and erase previous messages.
+   */
+  public function startCollectingMessages() {
+    $this->collectMessages = TRUE;
+    $this->migrateMessages = array();
+  }
+
+  /**
+   * Stop collecting messages.
+   */
+  public function stopCollectingMessages() {
+    $this->collectMessages = FALSE;
+  }
+
 }
diff --git a/core/modules/migrate/migrate.api.php b/core/modules/migrate/migrate.api.php
index a2d2cb5..c89614e 100644
--- a/core/modules/migrate/migrate.api.php
+++ b/core/modules/migrate/migrate.api.php
@@ -24,7 +24,7 @@
  * hook_migrate_MIGRATION_ID_prepare_row is also available.
  */
 function hook_migrate_prepare_row(Row $row, MigrateSourceInterface $source, MigrationInterface $migration) {
-  if ($migration->id() == 'drupal6_filter_formats') {
+  if ($migration->id() == 'd6_filter_formats') {
     $value = $source->getDatabase()->query('SELECT value FROM {variable} WHERE name = :name', array(':name' => 'mymodule_filter_foo_' . $row->getSourceProperty('format')))->fetchField();
     if ($value) {
       $row->setSourceProperty('settings:mymodule:foo', unserialize($value));
diff --git a/core/modules/migrate/migrate.services.yml b/core/modules/migrate/migrate.services.yml
index 11bead4..86aabe1 100644
--- a/core/modules/migrate/migrate.services.yml
+++ b/core/modules/migrate/migrate.services.yml
@@ -8,16 +8,19 @@ services:
     arguments: [migrate]
   plugin.manager.migrate.source:
     class: Drupal\migrate\Plugin\MigratePluginManager
-    arguments: [source, '@container.namespaces', '@cache.cache', '@language_manager', '@module_handler']
+    arguments: [source, '@container.namespaces', '@cache.cache', '@language_manager', '@module_handler', 'Drupal\migrate\Annotation\MigrateSource']
   plugin.manager.migrate.process:
-    class: Drupal\migrate\Plugin\MigratePluginManager
-    arguments: [process, '@container.namespaces', '@cache.cache', '@language_manager', '@module_handler', 'Drupal\migrate\Annotation\MigrateProcessPlugin']
+    class: Drupal\migrate\Plugin\MigrateProcessPluginManager
+    arguments: [process, '@container.namespaces', '@cache.cache', '@language_manager', '@module_handler']
   plugin.manager.migrate.destination:
-    class: Drupal\migrate\Plugin\MigratePluginManager
-    arguments: [destination, '@container.namespaces', '@cache.cache', '@language_manager', '@module_handler']
+    class: Drupal\migrate\Plugin\MigrateDestinationPluginManager
+    arguments: [destination, '@container.namespaces', '@cache.cache', '@language_manager', '@module_handler', '@theme_handler', '@entity.manager']
   plugin.manager.migrate.id_map:
     class: Drupal\migrate\Plugin\MigratePluginManager
     arguments: [id_map, '@container.namespaces', '@cache.cache', '@language_manager', '@module_handler']
   plugin.manager.migrate.entity_field:
     class: Drupal\migrate\Plugin\MigratePluginManager
     arguments: [entity_field, '@container.namespaces', '@cache.cache', '@language_manager', '@module_handler']
+  password_migrate:
+    class: Drupal\migrate\MigratePassword
+    arguments: ['@password_original']
diff --git a/core/modules/migrate/tests/Drupal/migrate/Tests/FakeDatabaseSchema.php b/core/modules/migrate/tests/Drupal/migrate/Tests/FakeDatabaseSchema.php
index 5c1424d..5ec9bc5 100644
--- a/core/modules/migrate/tests/Drupal/migrate/Tests/FakeDatabaseSchema.php
+++ b/core/modules/migrate/tests/Drupal/migrate/Tests/FakeDatabaseSchema.php
@@ -32,74 +32,128 @@ public function __construct(array &$database_contents) {
     $this->databaseContents = &$database_contents;
   }
 
+  /**
+   * {@inheritdoc}
+   */
   public function tableExists($table) {
     return in_array($table, array_keys($this->databaseContents));
   }
 
+  /**
+   * {@inheritdoc}
+   */
   public function prefixNonTable($table) {
     throw new \Exception(sprintf('Unsupported method "%s"', __METHOD__));
   }
 
+  /**
+   * {@inheritdoc}
+   */
   protected function buildTableNameCondition($table_name, $operator = '=', $add_prefix = TRUE) {
     throw new \Exception(sprintf('Unsupported method "%s"', __METHOD__));
   }
 
+  /**
+   * {@inheritdoc}
+   */
   protected function getPrefixInfo($table = 'default', $add_prefix = TRUE) {
     throw new \Exception(sprintf('Unsupported method "%s"', __METHOD__));
   }
 
+  /**
+   * {@inheritdoc}
+   */
   public function addField($table, $field, $spec, $keys_new = array()) {
     throw new \Exception(sprintf('Unsupported method "%s"', __METHOD__));
   }
 
+  /**
+   * {@inheritdoc}
+   */
   public function addIndex($table, $name, $fields) {
     throw new \Exception(sprintf('Unsupported method "%s"', __METHOD__));
   }
 
+  /**
+   * {@inheritdoc}
+   */
   public function addPrimaryKey($table, $fields) {
     throw new \Exception(sprintf('Unsupported method "%s"', __METHOD__));
   }
 
+  /**
+   * {@inheritdoc}
+   */
   public function addUniqueKey($table, $name, $fields) {
     throw new \Exception(sprintf('Unsupported method "%s"', __METHOD__));
   }
 
+  /**
+   * {@inheritdoc}
+   */
   public function changeField($table, $field, $field_new, $spec, $keys_new = array()) {
     throw new \Exception(sprintf('Unsupported method "%s"', __METHOD__));
   }
 
+  /**
+   * PHP magic __clone() method.
+   */
   public function __clone() {
     throw new \Exception(sprintf('Unsupported method "%s"', __METHOD__));
   }
 
+  /**
+   * {@inheritdoc}
+   */
   public function copyTable($source, $destination) {
     throw new \Exception(sprintf('Unsupported method "%s"', __METHOD__));
   }
 
+  /**
+   * {@inheritdoc}
+   */
   public function createTable($name, $table) {
     #throw new \Exception(sprintf('Unsupported method "%s"', __METHOD__));
   }
 
+  /**
+   * {@inheritdoc}
+   */
   public function dropField($table, $field) {
     throw new \Exception(sprintf('Unsupported method "%s"', __METHOD__));
   }
 
+  /**
+   * {@inheritdoc}
+   */
   public function dropIndex($table, $name) {
     throw new \Exception(sprintf('Unsupported method "%s"', __METHOD__));
   }
 
+  /**
+   * {@inheritdoc}
+   */
   public function dropPrimaryKey($table) {
     throw new \Exception(sprintf('Unsupported method "%s"', __METHOD__));
   }
 
+  /**
+   * {@inheritdoc}
+   */
   public function dropTable($table) {
     unset($this->databaseContents[$table]);
   }
 
+  /**
+   * {@inheritdoc}
+   */
   public function dropUniqueKey($table, $name) {
     throw new \Exception(sprintf('Unsupported method "%s"', __METHOD__));
   }
 
+  /**
+   * {@inheritdoc}
+   */
   public function fieldExists($table, $column) {
     if (!empty($this->databaseContents[$table])) {
       $row = reset($this->databaseContents[$table]);
@@ -110,42 +164,72 @@ public function fieldExists($table, $column) {
     }
   }
 
+  /**
+   * {@inheritdoc}
+   */
   public function fieldNames($fields) {
     throw new \Exception(sprintf('Unsupported method "%s"', __METHOD__));
   }
 
+  /**
+   * {@inheritdoc}
+   */
   public function fieldSetDefault($table, $field, $default) {
     throw new \Exception(sprintf('Unsupported method "%s"', __METHOD__));
   }
 
+  /**
+   * {@inheritdoc}
+   */
   public function fieldSetNoDefault($table, $field) {
     throw new \Exception(sprintf('Unsupported method "%s"', __METHOD__));
   }
 
+  /**
+   * {@inheritdoc}
+   */
   public function findTables($table_expression) {
     throw new \Exception(sprintf('Unsupported method "%s"', __METHOD__));
   }
 
+  /**
+   * {@inheritdoc}
+   */
   public function getFieldTypeMap() {
     throw new \Exception(sprintf('Unsupported method "%s"', __METHOD__));
   }
 
+  /**
+   * {@inheritdoc}
+   */
   public function indexExists($table, $name) {
     throw new \Exception(sprintf('Unsupported method "%s"', __METHOD__));
   }
 
+  /**
+   * {@inheritdoc}
+   */
   public function nextPlaceholder() {
     throw new \Exception(sprintf('Unsupported method "%s"', __METHOD__));
   }
 
+  /**
+   * {@inheritdoc}
+   */
   public function prepareComment($comment, $length = NULL) {
     throw new \Exception(sprintf('Unsupported method "%s"', __METHOD__));
   }
 
+  /**
+   * {@inheritdoc}
+   */
   public function renameTable($table, $new_name) {
     throw new \Exception(sprintf('Unsupported method "%s"', __METHOD__));
   }
 
+  /**
+   * {@inheritdoc}
+   */
   public function uniqueIdentifier() {
     return $this->uniqueIdentifier;
   }
diff --git a/core/modules/migrate/tests/Drupal/migrate/Tests/FakeMerge.php b/core/modules/migrate/tests/Drupal/migrate/Tests/FakeMerge.php
index 09d9e77..709e0db 100644
--- a/core/modules/migrate/tests/Drupal/migrate/Tests/FakeMerge.php
+++ b/core/modules/migrate/tests/Drupal/migrate/Tests/FakeMerge.php
@@ -25,7 +25,7 @@ class FakeMerge extends Merge {
    * @param string $table
    *   The database table to merge into.
    */
-  function __construct(array &$database_contents, $table) {
+  public function __construct(array &$database_contents, $table) {
     $this->databaseContents = &$database_contents;
     $this->table = $table;
     $this->conditionTable = $table;
diff --git a/core/modules/migrate/tests/Drupal/migrate/Tests/FakeSelect.php b/core/modules/migrate/tests/Drupal/migrate/Tests/FakeSelect.php
index bf49714..de2f546 100644
--- a/core/modules/migrate/tests/Drupal/migrate/Tests/FakeSelect.php
+++ b/core/modules/migrate/tests/Drupal/migrate/Tests/FakeSelect.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\migrate\Tests;
 
+use Drupal\Component\Utility\String;
 use Drupal\Core\Database\Connection;
 use Drupal\Core\Database\Query\Condition;
 use Drupal\Core\Database\Query\PlaceholderInterface;
@@ -87,7 +88,17 @@ public function addJoin($type, $table, $alias = NULL, $condition = NULL, $argume
       if ($type != 'INNER' && $type != 'LEFT') {
         throw new \Exception(sprintf('%s type not supported, only INNER and LEFT.', $type));
       }
-      if (!preg_match('/(\w+)\.(\w+)\s*=\s*(\w+)\.(\w+)/', $condition, $matches)) {
+      if (!preg_match('/^(\w+\.)?(\w+)\s*=\s*(\w+)\.(\w+)$/', $condition, $matches)) {
+        throw new \Exception('Only x.field1 = y.field2 conditions are supported.' . $condition);
+      }
+      if (!$matches[1] && count($this->tables) == 2) {
+        $aliases = array_keys($this->tables);
+        $matches[1] = $aliases[0];
+      }
+      else {
+        $matches[1] = substr($matches[1], 0, -1);
+      }
+      if (!$matches[1]) {
         throw new \Exception('Only x.field1 = y.field2 conditions are supported.' . $condition);
       }
       if ($matches[1] == $alias) {
@@ -518,7 +529,7 @@ public function fields($table_alias, array $fields = array()) {
         $fields = array_keys(reset($this->databaseContents[$table]));
       }
       else {
-        throw new \Exception('All fields on empty table is not supported.');
+        throw new \Exception(String::format('All fields on empty table @table is not supported.', array('@table' => $table)));
       }
     }
     return parent::fields($table_alias, $fields);
diff --git a/core/modules/migrate/tests/Drupal/migrate/Tests/MigrateExecutableTest.php b/core/modules/migrate/tests/Drupal/migrate/Tests/MigrateExecutableTest.php
index cd54fd9..e837e09 100644
--- a/core/modules/migrate/tests/Drupal/migrate/Tests/MigrateExecutableTest.php
+++ b/core/modules/migrate/tests/Drupal/migrate/Tests/MigrateExecutableTest.php
@@ -43,12 +43,8 @@ class MigrateExecutableTest extends MigrateTestCase {
    */
   protected $executable;
 
-  protected $mapJoinable = FALSE;
-
   protected $migrationConfiguration = array(
     'id' => 'test',
-    'limit' => array('unit' => 'second', 'value' => 1),
-    'timeThreshold' => 0.9,
   );
 
   /**
@@ -72,6 +68,8 @@ protected function setUp() {
 
     $this->executable = new TestMigrateExecutable($this->migration, $this->message);
     $this->executable->setTranslationManager($this->getStringTranslationStub());
+    $this->executable->setTimeThreshold(0.1);
+    $this->executable->limit = array('unit' => 'second', 'value' => 1);
   }
 
   /**
@@ -111,6 +109,15 @@ public function testImportWithValidRow() {
       ->disableOriginalConstructor()
       ->getMock();
 
+    $row->expects($this->once())
+      ->method('getSourceIdValues')
+      ->will($this->returnValue(array('id' => 'test')));
+
+    $this->idMap->expects($this->once())
+      ->method('lookupDestinationId')
+      ->with(array('id' => 'test'))
+      ->will($this->returnValue(array('test')));
+
     $source->expects($this->once())
       ->method('current')
       ->will($this->returnValue($row));
@@ -124,7 +131,7 @@ public function testImportWithValidRow() {
     $destination = $this->getMock('Drupal\migrate\Plugin\MigrateDestinationInterface');
     $destination->expects($this->once())
       ->method('import')
-      ->with($row)
+      ->with($row, array('test'))
       ->will($this->returnValue(array('id' => 'test')));
 
     $this->migration->expects($this->once())
@@ -142,6 +149,56 @@ public function testImportWithValidRow() {
   /**
    * Tests the import method with a valid row.
    */
+  public function testImportWithValidRowWithoutDestinationId() {
+    $source = $this->getMockSource();
+
+    $row = $this->getMockBuilder('Drupal\migrate\Row')
+      ->disableOriginalConstructor()
+      ->getMock();
+
+    $row->expects($this->once())
+      ->method('getSourceIdValues')
+      ->will($this->returnValue(array('id' => 'test')));
+
+    $this->idMap->expects($this->once())
+      ->method('lookupDestinationId')
+      ->with(array('id' => 'test'))
+      ->will($this->returnValue(array('test')));
+
+    $source->expects($this->once())
+      ->method('current')
+      ->will($this->returnValue($row));
+
+    $this->executable->setSource($source);
+
+    $this->migration->expects($this->once())
+      ->method('getProcessPlugins')
+      ->will($this->returnValue(array()));
+
+    $destination = $this->getMock('Drupal\migrate\Plugin\MigrateDestinationInterface');
+    $destination->expects($this->once())
+      ->method('import')
+      ->with($row, array('test'))
+      ->will($this->returnValue(TRUE));
+
+    $this->migration->expects($this->once())
+      ->method('getDestinationPlugin')
+      ->will($this->returnValue($destination));
+
+    $this->idMap->expects($this->never())
+      ->method('saveIdMapping');
+
+    $this->assertSame(MigrationInterface::RESULT_COMPLETED, $this->executable->import());
+
+    $this->assertSame(1, $this->executable->getSuccessesSinceFeedback());
+    $this->assertSame(1, $this->executable->getTotalSuccesses());
+    $this->assertSame(1, $this->executable->getTotalProcessed());
+    $this->assertSame(1, $this->executable->getProcessedSinceFeedback());
+  }
+
+  /**
+   * Tests the import method with a valid row.
+   */
   public function testImportWithValidRowNoDestinationValues() {
     $source = $this->getMockSource();
 
@@ -166,7 +223,7 @@ public function testImportWithValidRowNoDestinationValues() {
     $destination = $this->getMock('Drupal\migrate\Plugin\MigrateDestinationInterface');
     $destination->expects($this->once())
       ->method('import')
-      ->with($row)
+      ->with($row, array('test'))
       ->will($this->returnValue(array()));
 
     $this->migration->expects($this->once())
@@ -188,6 +245,11 @@ public function testImportWithValidRowNoDestinationValues() {
     $this->idMap->expects($this->once())
       ->method('saveMessage');
 
+    $this->idMap->expects($this->once())
+      ->method('lookupDestinationId')
+      ->with(array('id' => 'test'))
+      ->will($this->returnValue(array('test')));
+
     $this->message->expects($this->once())
       ->method('display')
       ->with('New object was not saved, no error provided');
@@ -223,7 +285,7 @@ public function testImportWithValidRowWithMigrateException() {
     $destination = $this->getMock('Drupal\migrate\Plugin\MigrateDestinationInterface');
     $destination->expects($this->once())
       ->method('import')
-      ->with($row)
+      ->with($row, array('test'))
       ->will($this->throwException(new MigrateException($exception_message)));
 
     $this->migration->expects($this->once())
@@ -241,6 +303,11 @@ public function testImportWithValidRowWithMigrateException() {
       ->method('display')
       ->with($exception_message);
 
+    $this->idMap->expects($this->once())
+      ->method('lookupDestinationId')
+      ->with(array('id' => 'test'))
+      ->will($this->returnValue(array('test')));
+
     $this->assertSame(MigrationInterface::RESULT_COMPLETED, $this->executable->import());
   }
 
@@ -272,7 +339,7 @@ public function testImportWithValidRowWithException() {
     $destination = $this->getMock('Drupal\migrate\Plugin\MigrateDestinationInterface');
     $destination->expects($this->once())
       ->method('import')
-      ->with($row)
+      ->with($row, array('test'))
       ->will($this->throwException(new \Exception($exception_message)));
 
     $this->migration->expects($this->once())
@@ -286,6 +353,11 @@ public function testImportWithValidRowWithException() {
     $this->idMap->expects($this->once())
       ->method('saveMessage');
 
+    $this->idMap->expects($this->once())
+      ->method('lookupDestinationId')
+      ->with(array('id' => 'test'))
+      ->will($this->returnValue(array('test')));
+
     $this->message->expects($this->once())
       ->method('display')
       ->with($exception_message);
@@ -301,10 +373,10 @@ public function testTimeOptionExceeded() {
     $this->executable->setTimeElapsed(1);
     $this->assertTrue($this->executable->timeOptionExceeded());
     // Assert time limit not exceeded.
-    $this->migration->set('limit', array('unit' => 'seconds', 'value' => (REQUEST_TIME - 3600)));
+    $this->executable->limit = array('unit' => 'seconds', 'value' => (REQUEST_TIME - 3600));
     $this->assertFalse($this->executable->timeOptionExceeded());
     // Assert no time limit.
-    $this->migration->set('limit', array());
+    $this->executable->limit = array();
     $this->assertFalse($this->executable->timeOptionExceeded());
   }
 
@@ -313,19 +385,19 @@ public function testTimeOptionExceeded() {
    */
   public function testGetTimeLimit() {
     // Assert time limit has a unit of one second (test configuration default).
-    $limit = $this->migration->get('limit');
+    $limit = $this->executable->limit;
     $this->assertArrayHasKey('unit', $limit);
     $this->assertSame('second', $limit['unit']);
     $this->assertSame($limit['value'], $this->executable->getTimeLimit());
     // Assert time limit has a unit of multiple seconds.
-    $this->migration->set('limit', array('unit' => 'seconds', 'value' => 30));
-    $limit = $this->migration->get('limit');
+    $this->executable->limit = array('unit' => 'seconds', 'value' => 30);
+    $limit = $this->executable->limit;
     $this->assertArrayHasKey('unit', $limit);
     $this->assertSame('seconds', $limit['unit']);
     $this->assertSame($limit['value'], $this->executable->getTimeLimit());
     // Assert no time limit.
-    $this->migration->set('limit', array());
-    $limit = $this->migration->get('limit');
+    $this->executable->limit = array();
+    $limit = $this->executable->limit;
     $this->assertArrayNotHasKey('unit', $limit);
     $this->assertArrayNotHasKey('value', $limit);
     $this->assertNull($this->executable->getTimeLimit());
diff --git a/core/modules/migrate/tests/Drupal/migrate/Tests/MigrateExecuteableMemoryExceededTest.php b/core/modules/migrate/tests/Drupal/migrate/Tests/MigrateExecuteableMemoryExceededTest.php
index d69873f..133402e 100644
--- a/core/modules/migrate/tests/Drupal/migrate/Tests/MigrateExecuteableMemoryExceededTest.php
+++ b/core/modules/migrate/tests/Drupal/migrate/Tests/MigrateExecuteableMemoryExceededTest.php
@@ -37,13 +37,6 @@ class MigrateExecuteableMemoryExceededTest extends MigrateTestCase {
   protected $executable;
 
   /**
-   * Whether the map is joinable, initialized to FALSE.
-   *
-   * @var bool
-   */
-  protected $mapJoinable = FALSE;
-
-  /**
    * The migration configuration, initialized to set the ID to test.
    *
    * @var array
@@ -97,7 +90,7 @@ protected function setUp() {
   protected function runMemoryExceededTest($message, $memory_exceeded, $memory_usage_first = NULL, $memory_usage_second = NULL, $memory_limit = NULL) {
     $this->executable->setMemoryLimit($memory_limit ?: $this->memoryLimit);
     $this->executable->setMemoryUsage($memory_usage_first ?: $this->memoryLimit, $memory_usage_second ?: $this->memoryLimit);
-    $this->migration->set('memoryThreshold', 0.85);
+    $this->executable->setMemoryThreshold(0.85);
     if ($message) {
       $this->executable->message->expects($this->at(0))
         ->method('display')
diff --git a/core/modules/migrate/tests/Drupal/migrate/Tests/MigrateSqlIdMapEnsureTablesTest.php b/core/modules/migrate/tests/Drupal/migrate/Tests/MigrateSqlIdMapEnsureTablesTest.php
index d63caa4..6727aab 100644
--- a/core/modules/migrate/tests/Drupal/migrate/Tests/MigrateSqlIdMapEnsureTablesTest.php
+++ b/core/modules/migrate/tests/Drupal/migrate/Tests/MigrateSqlIdMapEnsureTablesTest.php
@@ -18,30 +18,12 @@
 class MigrateSqlIdMapEnsureTablesTest extends MigrateTestCase {
 
   /**
-   * Whether the map is joinable, initialized to FALSE.
-   *
-   * @var bool
-   */
-  protected $mapJoinable = FALSE;
-
-  /**
    * The migration configuration, initialized to set the ID and destination IDs.
    *
    * @var array
    */
   protected $migrationConfiguration = array(
     'id' => 'sql_idmap_test',
-    'sourceIds' => array(
-      'source_id_property' => array(
-        'type' => 'int',
-      ),
-    ),
-    'destinationIds' => array(
-      'destination_id_property' => array(
-        'type' => 'varchar',
-        'length' => 255,
-      ),
-    ),
   );
 
   /**
@@ -88,9 +70,15 @@ public function testEnsureTablesNotExist() {
       'not null' => FALSE,
       'description' => 'Hash of source row data, for detecting changes',
     );
-    $fields['sourceid1'] = $this->migrationConfiguration['sourceIds']['source_id_property'];
-    $fields['destid1'] = $this->migrationConfiguration['destinationIds']['destination_id_property'];
-    $fields['destid1']['not null'] = FALSE;
+    $fields['sourceid1'] = array(
+      'type' => 'int',
+      'not null' => TRUE,
+    );
+    $fields['destid1'] = array(
+      'type' => 'varchar',
+      'length' => 255,
+      'not null' => FALSE,
+    );
     $map_table_schema = array(
       'description' => 'Mappings from source identifier value(s) to destination identifier value(s).',
       'fields' => $fields,
@@ -113,7 +101,10 @@ public function testEnsureTablesNotExist() {
       'unsigned' => TRUE,
       'not null' => TRUE,
     );
-    $fields['sourceid1'] = $this->migrationConfiguration['sourceIds']['source_id_property'];
+    $fields['sourceid1'] = array(
+      'type' => 'int',
+      'not null' => TRUE,
+    );
     $fields['level'] = array(
       'type' => 'int',
       'unsigned' => TRUE,
@@ -199,7 +190,31 @@ protected function runEnsureTablesTest($schema) {
     $database->expects($this->any())
       ->method('schema')
       ->will($this->returnValue($schema));
-    new TestSqlIdMap($database, array(), 'sql', array(), $this->getMigration());
+    $migration = $this->getMigration();
+    $plugin = $this->getMock('Drupal\migrate\Plugin\MigrateSourceInterface');
+    $plugin->expects($this->any())
+      ->method('getIds')
+      ->will($this->returnValue(array(
+      'source_id_property' => array(
+        'type' => 'integer',
+      ),
+    )));
+    $migration->expects($this->any())
+      ->method('getSourcePlugin')
+      ->will($this->returnValue($plugin));
+    $plugin = $this->getMock('Drupal\migrate\Plugin\MigrateSourceInterface');
+    $plugin->expects($this->any())
+      ->method('getIds')
+      ->will($this->returnValue(array(
+      'destination_id_property' => array(
+        'type' => 'string',
+      ),
+    )));
+    $migration->expects($this->any())
+      ->method('getDestinationPlugin')
+      ->will($this->returnValue($plugin));
+    $map = new TestSqlIdMap($database, array(), 'sql', array(), $migration);
+    $map->getDatabase();
   }
 
 }
diff --git a/core/modules/migrate/tests/Drupal/migrate/Tests/MigrateSqlIdMapTest.php b/core/modules/migrate/tests/Drupal/migrate/Tests/MigrateSqlIdMapTest.php
index 9bce172..1500618 100644
--- a/core/modules/migrate/tests/Drupal/migrate/Tests/MigrateSqlIdMapTest.php
+++ b/core/modules/migrate/tests/Drupal/migrate/Tests/MigrateSqlIdMapTest.php
@@ -21,25 +21,20 @@
 class MigrateSqlIdMapTest extends MigrateTestCase {
 
   /**
-   * Whether the map is joinable, initialized to FALSE.
-   *
-   * @var bool
-   */
-  protected $mapJoinable = FALSE;
-
-  /**
    * The migration configuration, initialized to set the ID and destination IDs.
    *
    * @var array
    */
   protected $migrationConfiguration = array(
     'id' => 'sql_idmap_test',
-    'sourceIds' => array(
-      'source_id_property' => array(),
-    ),
-    'destinationIds' => array(
-      'destination_id_property' => array(),
-    ),
+  );
+
+  protected $sourceIds = array(
+    'source_id_property' => array(),
+  );
+
+  protected $destinationIds = array(
+    'destination_id_property' => array(),
   );
 
   /**
@@ -76,6 +71,20 @@ public static function getInfo() {
    */
   protected function getIdMap($database_contents = array(), $connection_options = array(), $prefix = '') {
     $migration = $this->getMigration();
+    $plugin = $this->getMock('Drupal\migrate\Plugin\MigrateSourceInterface');
+    $plugin->expects($this->any())
+      ->method('getIds')
+      ->will($this->returnValue($this->sourceIds));
+    $migration->expects($this->any())
+      ->method('getSourcePlugin')
+      ->will($this->returnValue($plugin));
+    $plugin = $this->getMock('Drupal\migrate\Plugin\MigrateSourceInterface');
+    $plugin->expects($this->any())
+      ->method('getIds')
+      ->will($this->returnValue($this->destinationIds));
+    $migration->expects($this->any())
+      ->method('getDestinationPlugin')
+      ->will($this->returnValue($plugin));
     $this->database = $this->getDatabase($database_contents, $connection_options, $prefix);
     $id_map = new TestSqlIdMap($this->database, array(), 'sql', array(), $migration);
     $migration->expects($this->any())
@@ -246,7 +255,7 @@ public function testMessageSave() {
 
     foreach ($expected_results as $key => $expected_result) {
       $id_map->saveMessage(array($key), $message, $expected_result['level']);
-      $message_row = $this->database->select($id_map->getMessageTableName(), 'message')
+      $message_row = $this->database->select($id_map->messageTableName(), 'message')
                        ->fields('message')
                        ->condition('level',$expected_result['level'])
                        ->condition('message',$expected_result['message'])
@@ -258,7 +267,7 @@ public function testMessageSave() {
     // Insert with default level.
     $message_default = 'Hello world default.';
     $id_map->saveMessage(array(5), $message_default);
-    $message_row = $this->database->select($id_map->getMessageTableName(), 'message')
+    $message_row = $this->database->select($id_map->messageTableName(), 'message')
                      ->fields('message')
                      ->condition('level', MigrationInterface::MESSAGE_ERROR)
                      ->condition('message', $message_default)
@@ -319,8 +328,8 @@ public function testLookupDestinationIdMapping() {
   protected function performLookupDestinationIdTest($num_source_fields, $num_destination_fields) {
     // Adjust the migration configuration according to the number of source and
     // destination fields.
-    $this->migrationConfiguration['sourceIds'] = array();
-    $this->migrationConfiguration['destinationIds'] = array();
+    $this->sourceIds = array();
+    $this->destinationIds = array();
     $source_id_values = array();
     $nonexistent_id_values = array();
     $row = $this->idMapDefaults();
@@ -328,13 +337,13 @@ protected function performLookupDestinationIdTest($num_source_fields, $num_desti
       $row["sourceid$i"] = "source_id_value_$i";
       $source_id_values[] = "source_id_value_$i";
       $nonexistent_id_values[] = "nonexistent_source_id_value_$i";
-      $this->migrationConfiguration['sourceIds']["source_id_property_$i"] = array();
+      $this->sourceIds["source_id_property_$i"] = array();
     }
     $expected_result = array();
     for ($i = 1; $i <= $num_destination_fields; $i++) {
       $row["destid$i"] = "destination_id_value_$i";
       $expected_result[] = "destination_id_value_$i";
-      $this->migrationConfiguration['destinationIds']["destination_id_property_$i"] = array();
+      $this->destinationIds["destination_id_property_$i"] = array();
     }
     $database_contents['migrate_map_sql_idmap_test'][] = $row;
     $id_map = $this->getIdMap($database_contents);
@@ -400,14 +409,14 @@ public function testLookupSourceIDMapping() {
   protected function performLookupSourceIdTest($num_source_fields, $num_destination_fields) {
     // Adjust the migration configuration according to the number of source and
     // destination fields.
-    $this->migrationConfiguration['sourceIds'] = array();
-    $this->migrationConfiguration['destinationIds'] = array();
+    $this->sourceIds = array();
+    $this->destinationIds = array();
     $row = $this->idMapDefaults();
     $expected_result = array();
     for ($i = 1; $i <= $num_source_fields; $i++) {
       $row["sourceid$i"] = "source_id_value_$i";
       $expected_result[] = "source_id_value_$i";
-      $this->migrationConfiguration['sourceIds']["source_id_property_$i"] = array();
+      $this->sourceIds["source_id_property_$i"] = array();
     }
     $destination_id_values = array();
     $nonexistent_id_values = array();
@@ -415,7 +424,7 @@ protected function performLookupSourceIdTest($num_source_fields, $num_destinatio
       $row["destid$i"] = "destination_id_value_$i";
       $destination_id_values[] = "destination_id_value_$i";
       $nonexistent_id_values[] = "nonexistent_destination_id_value_$i";
-      $this->migrationConfiguration['destinationIds']["destination_id_property_$i"] = array();
+      $this->destinationIds["destination_id_property_$i"] = array();
     }
     $database_contents['migrate_map_sql_idmap_test'][] = $row;
     $id_map = $this->getIdMap($database_contents);
@@ -679,8 +688,10 @@ public function testPrepareUpdate() {
    */
   public function testDestroy() {
     $id_map = $this->getIdMap();
-    $map_table_name = $id_map->getMapTableName();
-    $message_table_name = $id_map->getMessageTableName();
+    // Initialize the id map.
+    $id_map->getDatabase();
+    $map_table_name = $id_map->mapTableName();
+    $message_table_name = $id_map->messageTableName();
     $row = new Row(array('source_id_property' => 'source_value'), array('source_id_property' => array()));
     $id_map->saveIdMapping($row, array('destination_id_property' => 2));
     $id_map->saveMessage(array('source_value'), 'A message');
@@ -710,7 +721,7 @@ public function testGetQualifiedMapTableNoPrefix() {
   public function testGetQualifiedMapTablePrefix() {
     $id_map = $this->getIdMap(array(), array('database' => 'source_database'), 'prefix');
     $qualified_map_table = $id_map->getQualifiedMapTableName();
-    $this->assertEquals('migrate_map_sql_idmap_test', $qualified_map_table);
+    $this->assertEquals('source_database.prefixmigrate_map_sql_idmap_test', $qualified_map_table);
   }
 
   /**
diff --git a/core/modules/migrate/tests/Drupal/migrate/Tests/MigrateSqlSourceTestCase.php b/core/modules/migrate/tests/Drupal/migrate/Tests/MigrateSqlSourceTestCase.php
index a8111c8..598db2c 100644
--- a/core/modules/migrate/tests/Drupal/migrate/Tests/MigrateSqlSourceTestCase.php
+++ b/core/modules/migrate/tests/Drupal/migrate/Tests/MigrateSqlSourceTestCase.php
@@ -6,6 +6,8 @@
  */
 
 namespace Drupal\migrate\Tests;
+use Drupal\Core\Cache\CacheBackendInterface;
+use Drupal\migrate\Source;
 
 /**
  * Provides setup and helper methods for Migrate module source tests.
@@ -15,7 +17,7 @@
   /**
    * The tested source plugin.
    *
-   * @var \Drupal\migrate\Plugin\migrate\source\d6\Drupal6SqlBase.
+   * @var \Drupal\migrate_drupal\Plugin\migrate\source\DrupalSqlBase.
    */
   protected $source;
 
@@ -69,9 +71,7 @@
    * {@inheritdoc}
    */
   protected function setUp() {
-    $module_handler = $this->getMockBuilder('Drupal\Core\Extension\ModuleHandlerInterface')
-      ->disableOriginalConstructor()
-      ->getMock();
+    $module_handler = $this->getMock('Drupal\Core\Extension\ModuleHandlerInterface');
 
     $migration = $this->getMigration();
     $migration->expects($this->any())
@@ -82,6 +82,7 @@ protected function setUp() {
     $plugin = new $plugin_class($this->migrationConfiguration['source'], $this->migrationConfiguration['source']['plugin'], array(), $migration);
     $plugin->setDatabase($this->getDatabase($this->databaseContents + array('test_map' => array())));
     $plugin->setModuleHandler($module_handler);
+    $plugin->setTranslationManager($this->getStringTranslationStub());
     $migration->expects($this->any())
       ->method('getSourcePlugin')
       ->will($this->returnValue($plugin));
@@ -94,6 +95,9 @@ protected function setUp() {
     $this->source->setCache($cache);
   }
 
+  /**
+   * Test the source returns the same rows as expected.
+   */
   public function testRetrieval() {
     $this->queryResultTest($this->source, $this->expectedResults);
   }
@@ -119,3 +123,9 @@ public static function getInfo() {
   }
 
 }
+
+class TestSource extends Source {
+  public function setCache(CacheBackendInterface $cache) {
+    $this->cache = $cache;
+  }
+}
diff --git a/core/modules/migrate/tests/Drupal/migrate/Tests/MigrateTestCase.php b/core/modules/migrate/tests/Drupal/migrate/Tests/MigrateTestCase.php
index ef94410..91e9fb0 100644
--- a/core/modules/migrate/tests/Drupal/migrate/Tests/MigrateTestCase.php
+++ b/core/modules/migrate/tests/Drupal/migrate/Tests/MigrateTestCase.php
@@ -14,13 +14,6 @@
  */
 abstract class MigrateTestCase extends UnitTestCase {
 
-  /**
-   * @TODO: does this need to be derived from the source/destination plugin?
-   *
-   * @var bool
-   */
-  protected $mapJoinable = TRUE;
-
   protected $migrationConfiguration = array();
 
   /**
@@ -32,13 +25,16 @@
   protected function getMigration() {
     $this->idMap = $this->getMock('Drupal\migrate\Plugin\MigrateIdMapInterface');
 
-    if ($this->mapJoinable) {
-      $this->idMap->expects($this->once())
-        ->method('getQualifiedMapTableName')
-        ->will($this->returnValue('test_map'));
-    }
+    $this->idMap->expects($this->any())
+      ->method('getQualifiedMapTableName')
+      ->will($this->returnValue('test_map'));
 
-    $migration = $this->getMock('Drupal\migrate\Entity\MigrationInterface');
+    $migration = $this->getMockBuilder('Drupal\migrate\Entity\Migration')
+      ->disableOriginalConstructor()
+      ->getMock();
+    $migration->expects($this->any())
+      ->method('checkRequirements')
+      ->will($this->returnValue(TRUE));
     $migration->expects($this->any())
       ->method('getIdMap')
       ->will($this->returnValue($this->idMap));
diff --git a/core/modules/migrate/tests/Drupal/migrate/Tests/RowTest.php b/core/modules/migrate/tests/Drupal/migrate/Tests/RowTest.php
index b337cdf..c30375c 100644
--- a/core/modules/migrate/tests/Drupal/migrate/Tests/RowTest.php
+++ b/core/modules/migrate/tests/Drupal/migrate/Tests/RowTest.php
@@ -248,8 +248,8 @@ public function testDestination() {
   public function testMultipleDestination() {
     $row = new Row($this->testValues, $this->testSourceIds);
     // Set some deep nested values.
-    $row->setDestinationProperty('image:alt', 'alt text');
-    $row->setDestinationProperty('image:fid', 3);
+    $row->setDestinationProperty('image.alt', 'alt text');
+    $row->setDestinationProperty('image.fid', 3);
 
     $this->assertTrue($row->hasDestinationProperty('image'));
     $this->assertFalse($row->hasDestinationProperty('alt'));
@@ -258,8 +258,8 @@ public function testMultipleDestination() {
     $destination = $row->getDestination();
     $this->assertEquals('alt text', $destination['image']['alt']);
     $this->assertEquals(3, $destination['image']['fid']);
-    $this->assertEquals('alt text', $row->getDestinationProperty('image:alt'));
-    $this->assertEquals(3, $row->getDestinationProperty('image:fid'));
+    $this->assertEquals('alt text', $row->getDestinationProperty('image.alt'));
+    $this->assertEquals(3, $row->getDestinationProperty('image.fid'));
   }
 
 }
diff --git a/core/modules/migrate/tests/Drupal/migrate/Tests/TestMigrateExecutable.php b/core/modules/migrate/tests/Drupal/migrate/Tests/TestMigrateExecutable.php
index 1a222c7..1ddfebf 100644
--- a/core/modules/migrate/tests/Drupal/migrate/Tests/TestMigrateExecutable.php
+++ b/core/modules/migrate/tests/Drupal/migrate/Tests/TestMigrateExecutable.php
@@ -222,6 +222,26 @@ public function setMemoryLimit($memory_limit) {
   }
 
   /**
+   * Sets the memory threshold.
+   *
+   * @param float $threshold
+   *   The new threshold.
+   */
+  public function setMemoryThreshold($threshold) {
+    $this->memoryThreshold = $threshold;
+  }
+
+  /**
+   * Sets the time threshold.
+   *
+   * @param float $threshold
+   *   The new threshold.
+   */
+  public function setTimeThreshold($threshold) {
+    $this->timeThreshold = $threshold;
+  }
+
+  /**
    * {@inheritdoc}
    */
   protected function formatSize($size) {
diff --git a/core/modules/migrate/tests/Drupal/migrate/Tests/TestSource.php b/core/modules/migrate/tests/Drupal/migrate/Tests/TestSource.php
deleted file mode 100644
index 99988d6..0000000
--- a/core/modules/migrate/tests/Drupal/migrate/Tests/TestSource.php
+++ /dev/null
@@ -1,18 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\migrate\Tests\TestSource.
- */
-
-
-namespace Drupal\migrate\Tests;
-
-use Drupal\Core\Cache\CacheBackendInterface;
-use Drupal\migrate\Source;
-
-class TestSource extends Source {
-  function setCache(CacheBackendInterface $cache) {
-    $this->cache = $cache;
-  }
-}
diff --git a/core/modules/migrate/tests/Drupal/migrate/Tests/TestSqlIdMap.php b/core/modules/migrate/tests/Drupal/migrate/Tests/TestSqlIdMap.php
index 76f59db..2914a7f 100644
--- a/core/modules/migrate/tests/Drupal/migrate/Tests/TestSqlIdMap.php
+++ b/core/modules/migrate/tests/Drupal/migrate/Tests/TestSqlIdMap.php
@@ -7,8 +7,10 @@
 
 namespace Drupal\migrate\Tests;
 
+use Drupal\Component\Utility\String;
 use Drupal\Core\Database\Connection;
 use Drupal\migrate\Entity\MigrationInterface;
+use Drupal\migrate\MigrateException;
 use Drupal\migrate\Plugin\migrate\id_map\Sql;
 
 /**
@@ -30,7 +32,7 @@ class TestSqlIdMap extends Sql implements \Iterator {
    * @param \Drupal\migrate\Entity\MigrationInterface $migration
    *   The migration to do.
    */
-  function __construct(Connection $database, array $configuration, $plugin_id, array $plugin_definition, MigrationInterface $migration) {
+  public function __construct(Connection $database, array $configuration, $plugin_id, array $plugin_definition, MigrationInterface $migration) {
     $this->database = $database;
     parent::__construct($configuration, $plugin_id, $plugin_definition, $migration);
   }
@@ -42,4 +44,24 @@ public function getDatabase() {
     return parent::getDatabase();
   }
 
+  protected function getFieldSchema(array $id_definition) {
+    if (!isset($id_definition['type'])) {
+      return array();
+    }
+    switch ($id_definition['type']) {
+      case 'integer':
+        return array(
+          'type' => 'int',
+          'not null' => TRUE,
+        );
+      case 'string':
+        return array(
+          'type' => 'varchar',
+          'length' => 255,
+          'not null' => FALSE,
+        );
+      default:
+        throw new MigrateException(String::format('@type not supported', array('@type' => $id_definition['type'])));
+    }
+  }
 }
diff --git a/core/modules/migrate/tests/Drupal/migrate/Tests/destination/PerComponentEntityDisplayTest.php b/core/modules/migrate/tests/Drupal/migrate/Tests/destination/PerComponentEntityDisplayTest.php
new file mode 100644
index 0000000..d36acb4
--- /dev/null
+++ b/core/modules/migrate/tests/Drupal/migrate/Tests/destination/PerComponentEntityDisplayTest.php
@@ -0,0 +1,78 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\migrate\Tests\destination\EntityDisplayTest.
+ */
+
+namespace Drupal\migrate\Tests\destination;
+
+use Drupal\migrate\Plugin\migrate\destination\ComponentEntityDisplayBase;
+use Drupal\migrate\Row;
+use Drupal\migrate\Tests\MigrateTestCase;
+
+/**
+ * Tests the entity display destination plugin.
+ *
+ * @group Drupal
+ * @group migrate
+ */
+class PerComponentEntityDisplayTest extends MigrateTestCase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function getInfo() {
+    return array(
+      'name' => 'Entity display destination plugin',
+      'description' => 'Tests the entity display destination plugin.',
+      'group' => 'Migrate',
+    );
+  }
+
+  /**
+   * Tests the entity display import method.
+   */
+  public function testImport() {
+    $values = array(
+      'entity_type' => 'entity_type_test',
+      'bundle' => 'bundle_test',
+      'view_mode' => 'view_mode_test',
+      'field_name' => 'field_name_test',
+      'options' => array('test setting'),
+    );
+    $row = new Row(array(), array());
+    foreach ($values as $key => $value) {
+      $row->setDestinationProperty($key, $value);
+    }
+    $entity = $this->getMockBuilder('Drupal\entity\Entity\EntityViewDisplay')
+      ->disableOriginalConstructor()
+      ->getMock();
+    $entity->expects($this->once())
+      ->method('setComponent')
+      ->with('field_name_test', array('test setting'))
+      ->will($this->returnSelf());
+    $entity->expects($this->once())
+      ->method('save')
+      ->with();
+    $plugin = new TestPerComponentEntityDisplay($entity);
+    $this->assertSame($plugin->import($row), array('entity_type_test', 'bundle_test', 'view_mode_test', 'field_name_test'));
+    $this->assertSame($plugin->getTestValues(), array('entity_type_test', 'bundle_test', 'view_mode_test'));
+  }
+
+}
+
+class TestPerComponentEntityDisplay extends ComponentEntityDisplayBase {
+  const MODE_NAME = 'view_mode';
+  protected $testValues;
+  public function __construct($entity) {
+    $this->entity = $entity;
+  }
+  protected function getEntity($entity_type, $bundle, $view_mode) {
+    $this->testValues = func_get_args();
+    return $this->entity;
+  }
+  public function getTestValues() {
+    return $this->testValues;
+  }
+}
diff --git a/core/modules/migrate/tests/Drupal/migrate/Tests/destination/PerComponentEntityFormDisplayTest.php b/core/modules/migrate/tests/Drupal/migrate/Tests/destination/PerComponentEntityFormDisplayTest.php
new file mode 100644
index 0000000..8d24988
--- /dev/null
+++ b/core/modules/migrate/tests/Drupal/migrate/Tests/destination/PerComponentEntityFormDisplayTest.php
@@ -0,0 +1,78 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\migrate\Tests\destination\EntityFormDisplayTest.
+ */
+
+namespace Drupal\migrate\Tests\destination;
+
+use Drupal\migrate\Plugin\migrate\destination\PerComponentEntityFormDisplay;
+use Drupal\migrate\Row;
+use Drupal\migrate\Tests\MigrateTestCase;
+
+/**
+ * Tests the entity display destination plugin.
+ *
+ * @group Drupal
+ * @group migrate
+ */
+class PerComponentEntityFormDisplayTest extends MigrateTestCase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function getInfo() {
+    return array(
+      'name' => 'Entity display destination plugin',
+      'description' => 'Tests the entity display destination plugin.',
+      'group' => 'Migrate',
+    );
+  }
+
+  /**
+   * Tests the entity display import method.
+   */
+  public function testImport() {
+    $values = array(
+      'entity_type' => 'entity_type_test',
+      'bundle' => 'bundle_test',
+      'form_mode' => 'form_mode_test',
+      'field_name' => 'field_name_test',
+      'options' => array('test setting'),
+    );
+    $row = new Row(array(), array());
+    foreach ($values as $key => $value) {
+      $row->setDestinationProperty($key, $value);
+    }
+    $entity = $this->getMockBuilder('Drupal\entity\Entity\EntityFormDisplay')
+      ->disableOriginalConstructor()
+      ->getMock();
+    $entity->expects($this->once())
+      ->method('setComponent')
+      ->with('field_name_test', array('test setting'))
+      ->will($this->returnSelf());
+    $entity->expects($this->once())
+      ->method('save')
+      ->with();
+    $plugin = new TestPerComponentEntityFormDisplay($entity);
+    $this->assertSame($plugin->import($row), array('entity_type_test', 'bundle_test', 'form_mode_test', 'field_name_test'));
+    $this->assertSame($plugin->getTestValues(), array('entity_type_test', 'bundle_test', 'form_mode_test'));
+  }
+
+}
+
+class TestPerComponentEntityFormDisplay extends PerComponentEntityFormDisplay {
+  const MODE_NAME = 'form_mode';
+  protected $testValues;
+  public function __construct($entity) {
+    $this->entity = $entity;
+  }
+  protected function getEntity($entity_type, $bundle, $form_mode) {
+    $this->testValues = func_get_args();
+    return $this->entity;
+  }
+  public function getTestValues() {
+    return $this->testValues;
+  }
+}
diff --git a/core/modules/migrate/tests/Drupal/migrate/Tests/process/CallbackTest.php b/core/modules/migrate/tests/Drupal/migrate/Tests/process/CallbackTest.php
new file mode 100644
index 0000000..c4ace45
--- /dev/null
+++ b/core/modules/migrate/tests/Drupal/migrate/Tests/process/CallbackTest.php
@@ -0,0 +1,65 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\migrate\Tests\process\CallbackTest.
+ */
+
+namespace Drupal\migrate\Tests\process;
+
+use Drupal\migrate\Plugin\migrate\process\Callback;
+
+/**
+ * @group migrate
+ * @group Drupal
+ */
+class CallbackTest extends MigrateProcessTestCase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function getInfo() {
+    return array(
+      'name' => 'Callback process plugin',
+      'description' => 'Tests the callback process plugin.',
+      'group' => 'Migrate',
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp() {
+    $this->plugin = new TestCallback();
+    parent::setUp();
+  }
+
+  /**
+   * Test callback with a function as callable.
+   */
+  public function testCallbackWithFunction() {
+    $this->plugin->setCallable('strtolower');
+    $value = $this->plugin->transform('FooBar', $this->migrateExecutable, $this->row, 'destinationproperty');
+    $this->assertSame($value, 'foobar');
+  }
+
+  /**
+   * Test callback with a class method as callable.
+   */
+  public function testCallbackWithClassMethod() {
+    $this->plugin->setCallable(array('\Drupal\Component\Utility\Unicode', 'strtolower'));
+    $value = $this->plugin->transform('FooBar', $this->migrateExecutable, $this->row, 'destinationproperty');
+    $this->assertSame($value, 'foobar');
+  }
+
+}
+
+class TestCallback extends Callback {
+  public function __construct() {
+  }
+
+  public function setCallable($callable) {
+    $this->configuration['callable'] = $callable;
+  }
+
+}
diff --git a/core/modules/migrate/tests/Drupal/migrate/Tests/process/ConcatTest.php b/core/modules/migrate/tests/Drupal/migrate/Tests/process/ConcatTest.php
new file mode 100644
index 0000000..4c01ab7
--- /dev/null
+++ b/core/modules/migrate/tests/Drupal/migrate/Tests/process/ConcatTest.php
@@ -0,0 +1,72 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\migrate\Tests\process\ConcatTest.
+ */
+
+namespace Drupal\migrate\Tests\process;
+
+use Drupal\migrate\Plugin\migrate\process\Concat;
+
+/**
+ * @group migrate
+ * @group Drupal
+ */
+class ConcatTest extends MigrateProcessTestCase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function getInfo() {
+    return array(
+      'name' => 'Concat process plugin',
+      'description' => 'Tests the concat process plugin.',
+      'group' => 'Migrate',
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp() {
+    $this->plugin = new TestConcat();
+    parent::setUp();
+  }
+
+  /**
+   * Test concat works without a delimiter.
+   */
+  public function testConcatWithoutDelimiter() {
+    $value = $this->plugin->transform(array('foo', 'bar'), $this->migrateExecutable, $this->row, 'destinationproperty');
+    $this->assertSame($value, 'foobar');
+  }
+
+  /**
+   * Test concat fails properly on non-arrays.
+   *
+   * @expectedException \Drupal\migrate\MigrateException
+   */
+  public function testConcatWithNonArray() {
+    $this->plugin->transform('foo', $this->migrateExecutable, $this->row, 'destinationproperty');
+  }
+
+  /**
+   * Test concat works without a delimiter.
+   */
+  public function testConcatWithDelimiter() {
+    $this->plugin->setDelimiter('_');
+    $value = $this->plugin->transform(array('foo', 'bar'), $this->migrateExecutable, $this->row, 'destinationproperty');
+    $this->assertSame($value, 'foo_bar');
+  }
+}
+
+class TestConcat extends Concat {
+  public function __construct() {
+  }
+
+  public function setDelimiter($delimiter) {
+    $this->configuration['delimiter'] = $delimiter;
+  }
+
+}
diff --git a/core/modules/migrate/tests/Drupal/migrate/Tests/process/DedupeEntityTest.php b/core/modules/migrate/tests/Drupal/migrate/Tests/process/DedupeEntityTest.php
index 4948dab..1060acd 100644
--- a/core/modules/migrate/tests/Drupal/migrate/Tests/process/DedupeEntityTest.php
+++ b/core/modules/migrate/tests/Drupal/migrate/Tests/process/DedupeEntityTest.php
@@ -40,7 +40,7 @@ public static function getInfo() {
   /**
    * {@inheritdoc}
    */
-  public function setUp() {
+  protected function setUp() {
     $this->entityQuery = $this->getMockBuilder('Drupal\Core\Entity\Query\QueryInterface')
       ->disableOriginalConstructor()
       ->getMock();
@@ -107,7 +107,7 @@ protected function entityQueryExpects($count) {
 }
 
 class TestDedupeEntity extends DedupeEntity {
-  function setEntityQuery(QueryInterface $entity_query) {
+  public function setEntityQuery(QueryInterface $entity_query) {
     $this->entityQuery = $entity_query;
   }
 }
diff --git a/core/modules/migrate/tests/Drupal/migrate/Tests/process/ExtractTest.php b/core/modules/migrate/tests/Drupal/migrate/Tests/process/ExtractTest.php
index 5e1e7d9..5266abf 100644
--- a/core/modules/migrate/tests/Drupal/migrate/Tests/process/ExtractTest.php
+++ b/core/modules/migrate/tests/Drupal/migrate/Tests/process/ExtractTest.php
@@ -31,7 +31,7 @@ public static function getInfo() {
   /**
    * {@inheritdoc}
    */
-  public function setUp() {
+  protected function setUp() {
     $configuration['index'] = array('foo');
     $this->plugin = new Extract($configuration, 'map', array());
     parent::setUp();
diff --git a/core/modules/migrate/tests/Drupal/migrate/Tests/process/GetTest.php b/core/modules/migrate/tests/Drupal/migrate/Tests/process/GetTest.php
index 60e66a7..a268e13 100644
--- a/core/modules/migrate/tests/Drupal/migrate/Tests/process/GetTest.php
+++ b/core/modules/migrate/tests/Drupal/migrate/Tests/process/GetTest.php
@@ -7,6 +7,7 @@
 namespace Drupal\migrate\Tests\process;
 
 use Drupal\migrate\Plugin\migrate\process\TestGet;
+use Drupal\migrate\Row;
 
 /**
  * @group migrate
@@ -28,7 +29,7 @@ public static function getInfo() {
   /**
    * {@inheritdoc}
    */
-  function setUp() {
+  protected function setUp() {
     $this->plugin = new TestGet();
     parent::setUp();
   }
@@ -36,7 +37,7 @@ function setUp() {
   /**
    * Tests the Get plugin when source is a string.
    */
-  function testTransformSourceString() {
+  public function testTransformSourceString() {
     $this->row->expects($this->once())
       ->method('getSourceProperty')
       ->with('test')
@@ -49,7 +50,7 @@ function testTransformSourceString() {
   /**
    * Tests the Get plugin when source is an array.
    */
-  function testTransformSourceArray() {
+  public function testTransformSourceArray() {
     $map = array(
       'test1' => 'source_value1',
       'test2' => 'source_value2',
@@ -65,7 +66,7 @@ function testTransformSourceArray() {
   /**
    * Tests the Get plugin when source is a string pointing to destination.
    */
-  function testTransformSourceStringAt() {
+  public function testTransformSourceStringAt() {
     $this->row->expects($this->once())
       ->method('getSourceProperty')
       ->with('@test')
@@ -78,7 +79,7 @@ function testTransformSourceStringAt() {
   /**
    * Tests the Get plugin when source is an array pointing to destination.
    */
-  function testTransformSourceArrayAt() {
+  public function testTransformSourceArrayAt() {
     $map = array(
       'test1' => 'source_value1',
       '@test2' => 'source_value2',
@@ -97,9 +98,9 @@ function testTransformSourceArrayAt() {
 namespace Drupal\migrate\Plugin\migrate\process;
 
 class TestGet extends Get {
-  function __construct() {
+  public function __construct() {
   }
-  function setSource($source) {
+  public function setSource($source) {
     $this->configuration['source'] = $source;
   }
 }
diff --git a/core/modules/migrate/tests/Drupal/migrate/Tests/process/IteratorTest.php b/core/modules/migrate/tests/Drupal/migrate/Tests/process/IteratorTest.php
index 454206f..9ca2f62 100644
--- a/core/modules/migrate/tests/Drupal/migrate/Tests/process/IteratorTest.php
+++ b/core/modules/migrate/tests/Drupal/migrate/Tests/process/IteratorTest.php
@@ -36,11 +36,6 @@ class IteratorTest extends MigrateTestCase {
   );
 
   /**
-   * @var bool
-   */
-  protected $mapJoinable = FALSE;
-
-  /**
    * {@inheritdoc}
    */
   public static function getInfo() {
diff --git a/core/modules/migrate/tests/Drupal/migrate/Tests/process/MachineNameTest.php b/core/modules/migrate/tests/Drupal/migrate/Tests/process/MachineNameTest.php
index 0c7b24b..c1c41c6 100644
--- a/core/modules/migrate/tests/Drupal/migrate/Tests/process/MachineNameTest.php
+++ b/core/modules/migrate/tests/Drupal/migrate/Tests/process/MachineNameTest.php
@@ -24,11 +24,6 @@ class MachineNameTest extends MigrateProcessTestCase {
   protected $transliteration;
 
   /**
-   * @var bool
-   */
-  protected $mapJoinable = FALSE;
-
-  /**
    * {@inheritdoc}
    */
   public static function getInfo() {
@@ -42,7 +37,7 @@ public static function getInfo() {
   /**
    * {@inheritdoc}
    */
-  public function setUp() {
+  protected function setUp() {
     $this->transliteration = $this->getMockBuilder('Drupal\Component\Transliteration\TransliterationInterface')
       ->disableOriginalConstructor()
       ->getMock();
diff --git a/core/modules/migrate/tests/Drupal/migrate/Tests/process/MigrateProcessTestCase.php b/core/modules/migrate/tests/Drupal/migrate/Tests/process/MigrateProcessTestCase.php
index 923ca97..4b45f35 100644
--- a/core/modules/migrate/tests/Drupal/migrate/Tests/process/MigrateProcessTestCase.php
+++ b/core/modules/migrate/tests/Drupal/migrate/Tests/process/MigrateProcessTestCase.php
@@ -26,7 +26,10 @@
    */
   protected $migrateExecutable;
 
-  function setUp() {
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp() {
     $this->row = $this->getMockBuilder('Drupal\migrate\Row')
       ->disableOriginalConstructor()
       ->getMock();
diff --git a/core/modules/migrate/tests/Drupal/migrate/Tests/process/StaticMapTest.php b/core/modules/migrate/tests/Drupal/migrate/Tests/process/StaticMapTest.php
index 5bd66cb..f7cf5a3 100644
--- a/core/modules/migrate/tests/Drupal/migrate/Tests/process/StaticMapTest.php
+++ b/core/modules/migrate/tests/Drupal/migrate/Tests/process/StaticMapTest.php
@@ -28,7 +28,7 @@ public static function getInfo() {
   /**
    * {@inheritdoc}
    */
-  function setUp() {
+  protected function setUp() {
     $this->row = $this->getMockBuilder('Drupal\migrate\Row')
       ->disableOriginalConstructor()
       ->getMock();
@@ -43,7 +43,7 @@ function setUp() {
   /**
    * Tests map when the source is a string.
    */
-  function testMapWithSourceString() {
+  public function testMapWithSourceString() {
     $value = $this->plugin->transform('foo', $this->migrateExecutable, $this->row, 'destinationproperty');
     $this->assertSame($value, array('bar' => 'baz'));
   }
@@ -51,7 +51,7 @@ function testMapWithSourceString() {
   /**
    * Tests map when the source is a list.
    */
-  function testMapWithSourceList() {
+  public function testMapWithSourceList() {
     $value = $this->plugin->transform(array('foo', 'bar'), $this->migrateExecutable, $this->row, 'destinationproperty');
     $this->assertSame($value, 'baz');
   }
@@ -61,7 +61,7 @@ function testMapWithSourceList() {
    *
    * @expectedException \Drupal\migrate\MigrateException
    */
-  function testMapwithEmptySource() {
+  public function testMapwithEmptySource() {
     $this->plugin->transform(array(), $this->migrateExecutable, $this->row, 'destinationproperty');
   }
 
@@ -70,7 +70,32 @@ function testMapwithEmptySource() {
    *
    * @expectedException \Drupal\migrate\MigrateException
    */
-  function testMapwithInvalidSource() {
+  public function testMapwithInvalidSource() {
+    $this->plugin->transform(array('bar'), $this->migrateExecutable, $this->row, 'destinationproperty');
+  }
+
+  /**
+   * Tests when the source is invalid but there's a default.
+   */
+  public function testMapWithInvalidSourceWithADefaultValue() {
+    $configuration['map']['foo']['bar'] = 'baz';
+    $configuration['default_value'] = 'test';
+    $this->plugin = new StaticMap($configuration, 'map', array());
+    $value = $this->plugin->transform(array('bar'), $this->migrateExecutable, $this->row, 'destinationproperty');
+    $this->assertSame($value, 'test');
+  }
+
+  /**
+   * Tests when the source is invalid and bypass is enabled.
+   *
+   * @expectedException \Drupal\migrate\MigrateException
+   * @expectedExceptionMessage Setting both default_value and bypass is invalid.
+   */
+  public function testMapWithInvalidSourceAndBypass() {
+    $configuration['map']['foo']['bar'] = 'baz';
+    $configuration['default_value'] = 'test';
+    $configuration['bypass'] = TRUE;
+    $this->plugin = new StaticMap($configuration, 'map', array());
     $this->plugin->transform(array('bar'), $this->migrateExecutable, $this->row, 'destinationproperty');
   }
 
diff --git a/core/modules/migrate_drupal/config/migrate.migration.d6_action_settings.yml b/core/modules/migrate_drupal/config/migrate.migration.d6_action_settings.yml
index 2da277f..d9da486 100644
--- a/core/modules/migrate_drupal/config/migrate.migration.d6_action_settings.yml
+++ b/core/modules/migrate_drupal/config/migrate.migration.d6_action_settings.yml
@@ -1,10 +1,10 @@
 id: d6_action_settings
 source:
-  plugin: drupal6_variable
+  plugin: variable
   variables:
     - actions_max_stack
 process:
   recursion_limit: actions_max_stack
 destination:
-  plugin: d8_config
+  plugin: config
   config_name: action.settings
diff --git a/core/modules/migrate_drupal/config/migrate.migration.d6_aggregator_settings.yml b/core/modules/migrate_drupal/config/migrate.migration.d6_aggregator_settings.yml
index a6ec30c..a5f99be 100644
--- a/core/modules/migrate_drupal/config/migrate.migration.d6_aggregator_settings.yml
+++ b/core/modules/migrate_drupal/config/migrate.migration.d6_aggregator_settings.yml
@@ -1,6 +1,6 @@
 id: d6_aggregator_settings
 source:
-  plugin: drupal6_variable
+  plugin: variable
   variables:
     - aggregator_fetcher
     - aggregator_parser
@@ -14,11 +14,11 @@ process:
   fetcher: aggregator_fetcher
   parser: aggregator_parser
   processors: aggregator_processors
-  'items:allowed_html': aggregator_allowed_html_tags
-  'items:teaser_length': aggregator_teaser_length
-  'items:expire': aggregator_clear
-  'source:list_max': aggregator_summary_items
-  'source:category_selector': aggregator_category_selector
+  'items.allowed_html': aggregator_allowed_html_tags
+  'items.teaser_length': aggregator_teaser_length
+  'items.expire': aggregator_clear
+  'source.list_max': aggregator_summary_items
+  'source.category_selector': aggregator_category_selector
 destination:
-  plugin: d8_config
+  plugin: config
   config_name: aggregator.settings
diff --git a/core/modules/migrate_drupal/config/migrate.migration.d6_book_settings.yml b/core/modules/migrate_drupal/config/migrate.migration.d6_book_settings.yml
index 77da0ce..9e1097f 100644
--- a/core/modules/migrate_drupal/config/migrate.migration.d6_book_settings.yml
+++ b/core/modules/migrate_drupal/config/migrate.migration.d6_book_settings.yml
@@ -1,14 +1,14 @@
 id: d6_book_settings
 source:
-  plugin: drupal6_variable
+  plugin: variable
   variables:
     - book_child_type
     - book_block_mode
     - book_allowed_types
 process:
   child_type: book_child_type
-  'block:navigation:mode': book_block_mode
+  'block.navigation.mode': book_block_mode
   allowed_types: book_allowed_types
 destination:
-  plugin: d8_config
+  plugin: config
   config_name: book.settings
diff --git a/core/modules/migrate_drupal/config/migrate.migration.d6_contact_settings.yml b/core/modules/migrate_drupal/config/migrate.migration.d6_contact_settings.yml
index 46470f8..823944d 100644
--- a/core/modules/migrate_drupal/config/migrate.migration.d6_contact_settings.yml
+++ b/core/modules/migrate_drupal/config/migrate.migration.d6_contact_settings.yml
@@ -1,12 +1,12 @@
 id: d6_contact_settings
 source:
-  plugin: drupal6_variable
+  plugin: variable
   variables:
     - contact_default_status
     - contact_hourly_threshold
 process:
   user_default_enabled: contact_default_status
-  'flood:limit': contact_hourly_threshold
+  'flood.limit': contact_hourly_threshold
 destination:
-  plugin: d8_config
+  plugin: config
   config_name: contact.settings
diff --git a/core/modules/migrate_drupal/config/migrate.migration.d6_dblog_settings.yml b/core/modules/migrate_drupal/config/migrate.migration.d6_dblog_settings.yml
index cea039f..b998cd6 100644
--- a/core/modules/migrate_drupal/config/migrate.migration.d6_dblog_settings.yml
+++ b/core/modules/migrate_drupal/config/migrate.migration.d6_dblog_settings.yml
@@ -1,10 +1,10 @@
 id: d6_dblog_settings
 source:
-  plugin: drupal6_variable
+  plugin: variable
   variables:
     - dblog_row_limit
 process:
   row_limit: dblog_row_limit
 destination:
-  plugin: d8_config
+  plugin: config
   config_name: dblog.settings
diff --git a/core/modules/migrate_drupal/config/migrate.migration.d6_field_settings.yml b/core/modules/migrate_drupal/config/migrate.migration.d6_field_settings.yml
index 45d6c34..902e155 100644
--- a/core/modules/migrate_drupal/config/migrate.migration.d6_field_settings.yml
+++ b/core/modules/migrate_drupal/config/migrate.migration.d6_field_settings.yml
@@ -1,10 +1,10 @@
 id: d6_field_settings
 source:
-  plugin: drupal6_variable
+  plugin: variable
   variables:
     - field_language_fallback
 process:
   language_fallback: field_language_fallback
 destination:
-  plugin: d8_config
+  plugin: config
   config_name: field.settings
diff --git a/core/modules/migrate_drupal/config/migrate.migration.d6_file_settings.yml b/core/modules/migrate_drupal/config/migrate.migration.d6_file_settings.yml
index 35e077b..a088b6c 100644
--- a/core/modules/migrate_drupal/config/migrate.migration.d6_file_settings.yml
+++ b/core/modules/migrate_drupal/config/migrate.migration.d6_file_settings.yml
@@ -1,14 +1,14 @@
 id: d6_file_settings
 source:
-  plugin: drupal6_variable
+  plugin: variable
   variables:
     - file_description_type
     - file_description_length
     - file_icon_directory
 process:
-  'description:type': file_description_type
-  'description:length': file_description_length
-  'icon:directory': file_icon_directory
+  'description.type': file_description_type
+  'description.length': file_description_length
+  'icon.directory': file_icon_directory
 destination:
-  plugin: d8_config
+  plugin: config
   config_name: file.settings
diff --git a/core/modules/migrate_drupal/config/migrate.migration.d6_forum_settings.yml b/core/modules/migrate_drupal/config/migrate.migration.d6_forum_settings.yml
index 5bb0a1f..8ed1bd2 100644
--- a/core/modules/migrate_drupal/config/migrate.migration.d6_forum_settings.yml
+++ b/core/modules/migrate_drupal/config/migrate.migration.d6_forum_settings.yml
@@ -1,6 +1,6 @@
 id: d6_forum_settings
 source:
-  plugin: drupal6_variable
+  plugin: variable
   variables:
     - forum_hot_topic
     - forum_per_page
@@ -8,11 +8,11 @@ source:
     - forum_block_num_0
     - forum_block_num_1
 process:
-  'block:active:limit': forum_block_num_0
-  'block:new:limit': forum_block_num_1
-  'topics:hot_threshold': forum_hot_topic
-  'topics:page_limit': forum_per_page
-  'topics:order': forum_order
+  'block.active.limit': forum_block_num_0
+  'block.new.limit': forum_block_num_1
+  'topics.hot_threshold': forum_hot_topic
+  'topics.page_limit': forum_per_page
+  'topics.order': forum_order
 destination:
-  plugin: d8_config
+  plugin: config
   config_name: forum.settings
diff --git a/core/modules/migrate_drupal/config/migrate.migration.d6_locale_settings.yml b/core/modules/migrate_drupal/config/migrate.migration.d6_locale_settings.yml
index 1183b5e..972aaff 100644
--- a/core/modules/migrate_drupal/config/migrate.migration.d6_locale_settings.yml
+++ b/core/modules/migrate_drupal/config/migrate.migration.d6_locale_settings.yml
@@ -1,12 +1,12 @@
 id: d6_locale_settings
 source:
-  plugin: drupal6_variable
+  plugin: variable
   variables:
     - locale_cache_strings
     - locale_js_directory
 process:
   cache_string: locale_cache_strings
-  'javascript:directory': locale_js_directory
+  'javascript.directory': locale_js_directory
 destination:
-  plugin: d8_config
+  plugin: config
   config_name: locale.settings
diff --git a/core/modules/migrate_drupal/config/migrate.migration.d6_menu_settings.yml b/core/modules/migrate_drupal/config/migrate.migration.d6_menu_settings.yml
index b57bd3e..5c56ea4 100644
--- a/core/modules/migrate_drupal/config/migrate.migration.d6_menu_settings.yml
+++ b/core/modules/migrate_drupal/config/migrate.migration.d6_menu_settings.yml
@@ -1,6 +1,6 @@
 id: d6_menu_settings
 source:
-    plugin: drupal6_variable
+    plugin: variable
     variables:
         - menu_primary_links_source
         - menu_secondary_links_source
@@ -10,5 +10,5 @@ process:
     secondary_links: menu_secondary_links_source
     override_parent_selector: menu_override_parent_selector
 destination:
-    plugin: d8_config
+    plugin: config
     config_name: menu.settings
diff --git a/core/modules/migrate_drupal/config/migrate.migration.d6_node_settings.yml b/core/modules/migrate_drupal/config/migrate.migration.d6_node_settings.yml
index ab37378..27e89b1 100644
--- a/core/modules/migrate_drupal/config/migrate.migration.d6_node_settings.yml
+++ b/core/modules/migrate_drupal/config/migrate.migration.d6_node_settings.yml
@@ -1,10 +1,12 @@
 id: d6_node_settings
 source:
-  plugin: drupal6_variable
+  plugin: variable
   variables:
     - node_admin_theme
 process:
   use_admin_theme: node_admin_theme
 destination:
-  plugin: d8_config
+  plugin: config
   config_name: node.settings
+dependencies:
+  - d6_node_type
diff --git a/core/modules/migrate_drupal/config/migrate.migration.d6_search_settings.yml b/core/modules/migrate_drupal/config/migrate.migration.d6_search_settings.yml
index 7ea5c20..b5c94b4 100644
--- a/core/modules/migrate_drupal/config/migrate.migration.d6_search_settings.yml
+++ b/core/modules/migrate_drupal/config/migrate.migration.d6_search_settings.yml
@@ -1,6 +1,6 @@
 id: d6_search_settings
 source:
-    plugin: drupal6_variable
+    plugin: variable
     variables:
         - minimum_word_size
         - overlap_cjk
@@ -8,9 +8,9 @@ source:
         - search_tag_weights
         - search_and_or_limit
 process:
-    'index:minimum_word_size': minimum_word_size
-    'index:overlap_cjk': overlap_cjk
-    'index:cron_limit': search_cron_limit
+    'index.minimum_word_size': minimum_word_size
+    'index.overlap_cjk': overlap_cjk
+    'index.cron_limit': search_cron_limit
 destination:
-    plugin: d8_config
+    plugin: config
     config_name: search.settings
diff --git a/core/modules/migrate_drupal/config/migrate.migration.d6_simpletest_settings.yml b/core/modules/migrate_drupal/config/migrate.migration.d6_simpletest_settings.yml
index 8a6f06c..f9cd2bb 100644
--- a/core/modules/migrate_drupal/config/migrate.migration.d6_simpletest_settings.yml
+++ b/core/modules/migrate_drupal/config/migrate.migration.d6_simpletest_settings.yml
@@ -1,6 +1,6 @@
 id: d6_simpletest_settings
 source:
-  plugin: drupal6_variable
+  plugin: variable
   variables:
     - simpletest_clear_results
     - simpletest_httpauth_method
@@ -9,10 +9,10 @@ source:
     - simpletest_verbose
 process:
   clear_results: simpletest_clear_results
-  'httpauth:method': simpletest_httpauth_method
-  'httpauth:password': simpletest_httpauth_password
-  'httpauth:username': simpletest_httpauth_username
+  'httpauth.method': simpletest_httpauth_method
+  'httpauth.password': simpletest_httpauth_password
+  'httpauth.username': simpletest_httpauth_username
   verbose: simpletest_verbose
 destination:
-  plugin: d8_config
+  plugin: config
   config_name: simpletest.settings
diff --git a/core/modules/migrate_drupal/config/migrate.migration.d6_statistics_settings.yml b/core/modules/migrate_drupal/config/migrate.migration.d6_statistics_settings.yml
index 24a1baf..e20849b 100644
--- a/core/modules/migrate_drupal/config/migrate.migration.d6_statistics_settings.yml
+++ b/core/modules/migrate_drupal/config/migrate.migration.d6_statistics_settings.yml
@@ -1,6 +1,6 @@
 id: d6_statistics_settings
 source:
-  plugin: drupal6_variable
+  plugin: variable
   variables:
     - statistics_enable_access_log
     - statistics_flush_accesslog_timer
@@ -9,12 +9,12 @@ source:
     - statistics_block_top_all_num
     - statistics_block_top_last_num
 process:
-  'access_log:enable': statistics_enable_access_log
-  'access_log:max_lifetime': statistics_flush_accesslog_timer
+  'access_log.enable': statistics_enable_access_log
+  'access_log.max_lifetime': statistics_flush_accesslog_timer
   'count_content_views': statistics_count_content_views
-  'block:popular:top_day_limit': statistics_block_top_day_num
-  'block:popular:top_all_limit': statistics_block_top_all_num
-  'block:popular:top_recent_limit': statistics_block_top_last_num
+  'block.popular.top_day_limit': statistics_block_top_day_num
+  'block.popular.top_all_limit': statistics_block_top_all_num
+  'block.popular.top_recent_limit': statistics_block_top_last_num
 destination:
-  plugin: d8_config
+  plugin: config
   config_name: statistics.settings
diff --git a/core/modules/migrate_drupal/config/migrate.migration.d6_syslog_settings.yml b/core/modules/migrate_drupal/config/migrate.migration.d6_syslog_settings.yml
index 8be7bf2..47c3072 100644
--- a/core/modules/migrate_drupal/config/migrate.migration.d6_syslog_settings.yml
+++ b/core/modules/migrate_drupal/config/migrate.migration.d6_syslog_settings.yml
@@ -1,6 +1,6 @@
 id: d6_syslog_settings
 source:
-  plugin: drupal6_variable
+  plugin: variable
   variables:
     - syslog_identity
     - syslog_facility
@@ -8,5 +8,5 @@ process:
   identity: syslog_identity
   facility: syslog_facility
 destination:
-  plugin: d8_config
+  plugin: config
   config_name: syslog.settings
diff --git a/core/modules/migrate_drupal/config/migrate.migration.d6_system_cron.yml b/core/modules/migrate_drupal/config/migrate.migration.d6_system_cron.yml
index 1e0e452..73a8b34 100644
--- a/core/modules/migrate_drupal/config/migrate.migration.d6_system_cron.yml
+++ b/core/modules/migrate_drupal/config/migrate.migration.d6_system_cron.yml
@@ -1,13 +1,13 @@
 id: d6_system_cron
 source:
-  plugin: drupal6_variable
+  plugin: variable
   variables:
     - cron_threshold_warning
     - cron_threshold_error
     - cron_last
 process:
-  'threshold:warning': cron_threshold_warning
-  'threshold:error': cron_threshold_error
+  'threshold.warning': cron_threshold_warning
+  'threshold.error': cron_threshold_error
 destination:
-  plugin: d8_config
+  plugin: config
   config_name: system.cron
diff --git a/core/modules/migrate_drupal/config/migrate.migration.d6_system_file.yml b/core/modules/migrate_drupal/config/migrate.migration.d6_system_file.yml
index df0797d..3c7cd3a 100644
--- a/core/modules/migrate_drupal/config/migrate.migration.d6_system_file.yml
+++ b/core/modules/migrate_drupal/config/migrate.migration.d6_system_file.yml
@@ -1,12 +1,12 @@
 id: d6_system_file
 source:
-  plugin: drupal6_variable
+  plugin: variable
   variables:
     - file_directory_path
     - file_directory_temp
 process:
-  'path:private': file_directory_path
-  'path:temporary': file_directory_temp
+  'path.private': file_directory_path
+  'path.temporary': file_directory_temp
 destination:
-  plugin: d8_config
+  plugin: config
   config_name: system.file
diff --git a/core/modules/migrate_drupal/config/migrate.migration.d6_system_filter.yml b/core/modules/migrate_drupal/config/migrate.migration.d6_system_filter.yml
index 0a2690e..2ca5770 100644
--- a/core/modules/migrate_drupal/config/migrate.migration.d6_system_filter.yml
+++ b/core/modules/migrate_drupal/config/migrate.migration.d6_system_filter.yml
@@ -1,10 +1,10 @@
 id: d6_system_filter
 source:
-  plugin: drupal6_variable
+  plugin: variable
   variables:
     - filter_allowed_protocols
 process:
   protocols: filter_allowed_protocols
 destination:
-  plugin: d8_config
+  plugin: config
   config_name: system.filter
diff --git a/core/modules/migrate_drupal/config/migrate.migration.d6_system_image.yml b/core/modules/migrate_drupal/config/migrate.migration.d6_system_image.yml
index 6d98bfc..d7caf6a 100644
--- a/core/modules/migrate_drupal/config/migrate.migration.d6_system_image.yml
+++ b/core/modules/migrate_drupal/config/migrate.migration.d6_system_image.yml
@@ -1,10 +1,10 @@
 id: d6_system_image
 source:
-  plugin: drupal6_variable
+  plugin: variable
   variables:
     - image_toolkit
 process:
   toolkit: image_toolkit
 destination:
-  plugin: d8_config
+  plugin: config
   config_name: system.image
diff --git a/core/modules/migrate_drupal/config/migrate.migration.d6_system_image_gd.yml b/core/modules/migrate_drupal/config/migrate.migration.d6_system_image_gd.yml
index 29aacba..f5bebe5 100644
--- a/core/modules/migrate_drupal/config/migrate.migration.d6_system_image_gd.yml
+++ b/core/modules/migrate_drupal/config/migrate.migration.d6_system_image_gd.yml
@@ -1,10 +1,10 @@
 id: d6_system_image_gd
 source:
-  plugin: drupal6_variable
+  plugin: variable
   variables:
     - image_jpeg_quality
 process:
   jpeg_quality: image_jpeg_quality
 destination:
-  plugin: d8_config
+  plugin: config
   config_name: system.image.gd
diff --git a/core/modules/migrate_drupal/config/migrate.migration.d6_system_maintenance.yml b/core/modules/migrate_drupal/config/migrate.migration.d6_system_maintenance.yml
index a711614..46e7708 100644
--- a/core/modules/migrate_drupal/config/migrate.migration.d6_system_maintenance.yml
+++ b/core/modules/migrate_drupal/config/migrate.migration.d6_system_maintenance.yml
@@ -1,6 +1,6 @@
 id: d6_system_maintenance
 source:
-  plugin: drupal6_variable
+  plugin: variable
   variables:
     - site_offline
     - site_offline_message
@@ -8,5 +8,5 @@ process:
   enable: site_offline
   message: site_offline_message
 destination:
-  plugin: d8_config
+  plugin: config
   config_name: system.maintenance
diff --git a/core/modules/migrate_drupal/config/migrate.migration.d6_system_performance.yml b/core/modules/migrate_drupal/config/migrate.migration.d6_system_performance.yml
index 6498d9e..fa83c7f 100644
--- a/core/modules/migrate_drupal/config/migrate.migration.d6_system_performance.yml
+++ b/core/modules/migrate_drupal/config/migrate.migration.d6_system_performance.yml
@@ -1,14 +1,14 @@
 id: d6_system_performance
 source:
-  plugin: drupal6_variable
+  plugin: variable
   variables:
     - preprocess_css
     - preprocess_js
     - cache_lifetime
 process:
-  'css:preprocess': preprocess_css
-  'js:preprocess': preprocess_js
-  'cache:page:max_age': cache_lifetime
+  'css.preprocess': preprocess_css
+  'js.preprocess': preprocess_js
+  'cache.page.max_age': cache_lifetime
 destination:
-  plugin: d8_config
+  plugin: config
   config_name: system.performance
diff --git a/core/modules/migrate_drupal/config/migrate.migration.d6_system_rss.yml b/core/modules/migrate_drupal/config/migrate.migration.d6_system_rss.yml
index ca8498f..ced4769 100644
--- a/core/modules/migrate_drupal/config/migrate.migration.d6_system_rss.yml
+++ b/core/modules/migrate_drupal/config/migrate.migration.d6_system_rss.yml
@@ -1,10 +1,10 @@
 id: d6_system_rss
 source:
-  plugin: drupal6_variable
+  plugin: variable
   variables:
     - feed_default_items
 process:
-  'items:limit': feed_default_items
+  'items.limit': feed_default_items
 destination:
-  plugin: d8_config
+  plugin: config
   config_name: system.rss
diff --git a/core/modules/migrate_drupal/config/migrate.migration.d6_system_site.yml b/core/modules/migrate_drupal/config/migrate.migration.d6_system_site.yml
index de88ed4..0bfe4e6 100644
--- a/core/modules/migrate_drupal/config/migrate.migration.d6_system_site.yml
+++ b/core/modules/migrate_drupal/config/migrate.migration.d6_system_site.yml
@@ -1,6 +1,6 @@
 id: d6_system_site
 source:
-  plugin: drupal6_variable
+  plugin: variable
   variables:
     - site_name
     - site_mail
@@ -14,11 +14,11 @@ process:
   name: site_name
   mail: site_mail
   slogan: site_slogan
-  'page:front': site_frontpage
-  'page:403': site_403
-  'page:404': site_404
+  'page.front': site_frontpage
+  'page.403': site_403
+  'page.404': site_404
   weight_select_max: drupal_weight_select_max
   admin_compact_mode: admin_compact_mode
 destination:
-  plugin: d8_config
+  plugin: config
   config_name: system.site
diff --git a/core/modules/migrate_drupal/config/migrate.migration.d6_system_theme.yml b/core/modules/migrate_drupal/config/migrate.migration.d6_system_theme.yml
index ba78e8c..8c1ffd8 100644
--- a/core/modules/migrate_drupal/config/migrate.migration.d6_system_theme.yml
+++ b/core/modules/migrate_drupal/config/migrate.migration.d6_system_theme.yml
@@ -1,6 +1,6 @@
 id: d6_system_theme
 source:
-  plugin: drupal6_variable
+  plugin: variable
   variables:
     - admin_theme
     - theme_default
@@ -8,5 +8,5 @@ process:
   admin: admin_theme
   default: theme_default
 destination:
-  plugin: d8_config
+  plugin: config
   config_name: system.theme
diff --git a/core/modules/migrate_drupal/config/migrate.migration.d6_taxonomy_settings.yml b/core/modules/migrate_drupal/config/migrate.migration.d6_taxonomy_settings.yml
index a6bbaf7..78caf05 100644
--- a/core/modules/migrate_drupal/config/migrate.migration.d6_taxonomy_settings.yml
+++ b/core/modules/migrate_drupal/config/migrate.migration.d6_taxonomy_settings.yml
@@ -1,6 +1,6 @@
 id: d6_taxonomy_settings
 source:
-  plugin: drupal6_variable
+  plugin: variable
   variables:
     - taxonomy_override_selector
     - taxonomy_terms_per_page_admin
@@ -8,5 +8,5 @@ process:
   override_selector: taxonomy_override_selector
   terms_per_page_admin: taxonomy_terms_per_page_admin
 destination:
-  plugin: d8_config
+  plugin: config
   config_name: taxonomy.settings
diff --git a/core/modules/migrate_drupal/config/migrate.migration.d6_text_settings.yml b/core/modules/migrate_drupal/config/migrate.migration.d6_text_settings.yml
index fb5dea5..e2e5fbd 100644
--- a/core/modules/migrate_drupal/config/migrate.migration.d6_text_settings.yml
+++ b/core/modules/migrate_drupal/config/migrate.migration.d6_text_settings.yml
@@ -1,10 +1,10 @@
 id: d6_text_settings
 source:
-  plugin: drupal6_variable
+  plugin: variable
   variables:
     - teaser_length
 process:
   default_summary_length: teaser_length
 destination:
-  plugin: d8_config
+  plugin: config
   config_name: text.settings
diff --git a/core/modules/migrate_drupal/config/migrate.migration.d6_update_settings.yml b/core/modules/migrate_drupal/config/migrate.migration.d6_update_settings.yml
index a3ab12a..6004b36 100644
--- a/core/modules/migrate_drupal/config/migrate.migration.d6_update_settings.yml
+++ b/core/modules/migrate_drupal/config/migrate.migration.d6_update_settings.yml
@@ -1,16 +1,16 @@
 id: d6_update_settings
 source:
-  plugin: drupal6_variable
+  plugin: variable
   variables:
     - update_max_fetch_attempts
     - update_fetch_url
     - update_notification_threshold
     - update_notify_emails
 process:
-  'fetch:max_attempts': update_max_fetch_attempts
-  'fetch:url': update_fetch_url
-  'notification:threshold': update_notification_threshold
-  'notification:mails': update_notify_emails
+  'fetch.max_attempts': update_max_fetch_attempts
+  'fetch.url': update_fetch_url
+  'notification.threshold': update_notification_threshold
+  'notification.mails': update_notify_emails
 destination:
-  plugin: d8_config
+  plugin: config
   config_name: update.settings
diff --git a/core/modules/migrate_drupal/config/migrate.migration.d6_user_mail.yml b/core/modules/migrate_drupal/config/migrate.migration.d6_user_mail.yml
index 1450402..75dee05 100644
--- a/core/modules/migrate_drupal/config/migrate.migration.d6_user_mail.yml
+++ b/core/modules/migrate_drupal/config/migrate.migration.d6_user_mail.yml
@@ -1,6 +1,6 @@
 id: d6_user_mail
 source:
-  plugin: drupal6_variable
+  plugin: variable
   variables:
     - user_mail_status_activated_subject
     - user_mail_status_activated_body
@@ -17,20 +17,20 @@ source:
     - user_mail_status_blocked_subject
     - user_mail_status_blocked_body
 process:
-  'status_activated:subject': user_mail_status_activated_subject
-  'status_activated:body': user_mail_status_activated_body
-  'password_reset:subject': user_mail_password_reset_subject
-  'password_reset:body': user_mail_password_reset_body
-  'cancel_confirm:subject': user_mail_status_deleted_subject
-  'cancel_confirm:body': user_mail_status_deleted_body
-  'register_admin_created:subject': user_mail_register_admin_created_subject
-  'register_admin_created:body': user_mail_register_admin_created_body
-  'register_no_approval_required:subject': user_mail_register_no_approval_required_subject
-  'register_no_approval_required:body': user_mail_register_no_approval_required_body
-  'register_pending_approval:subject': user_mail_user_mail_register_pending_approval_subject
-  'register_pending_approval:body': user_mail_user_mail_register_pending_approval_body
-  'status_blocked:subject': user_mail_status_blocked_subject
-  'status_blocked:body': user_mail_status_blocked_body
+  'status_activated.subject': user_mail_status_activated_subject
+  'status_activated.body': user_mail_status_activated_body
+  'password_reset.subject': user_mail_password_reset_subject
+  'password_reset.body': user_mail_password_reset_body
+  'cancel_confirm.subject': user_mail_status_deleted_subject
+  'cancel_confirm.body': user_mail_status_deleted_body
+  'register_admin_created.subject': user_mail_register_admin_created_subject
+  'register_admin_created.body': user_mail_register_admin_created_body
+  'register_no_approval_required.subject': user_mail_register_no_approval_required_subject
+  'register_no_approval_required.body': user_mail_register_no_approval_required_body
+  'register_pending_approval.subject': user_mail_user_mail_register_pending_approval_subject
+  'register_pending_approval.body': user_mail_user_mail_register_pending_approval_body
+  'status_blocked.subject': user_mail_status_blocked_subject
+  'status_blocked.body': user_mail_status_blocked_body
 destination:
-  plugin: d8_config
+  plugin: config
   config_name: user.mail
diff --git a/core/modules/migrate_drupal/config/migrate.migration.d6_user_role.yml b/core/modules/migrate_drupal/config/migrate.migration.d6_user_role.yml
index 3ee7334..b2372b5 100644
--- a/core/modules/migrate_drupal/config/migrate.migration.d6_user_role.yml
+++ b/core/modules/migrate_drupal/config/migrate.migration.d6_user_role.yml
@@ -1,15 +1,6 @@
 id: d6_user_role
-sourceIds:
-  rid:
-    type: int
-    "not null": true
-    default: 0
-destinationIds:
-  id:
-    type: varchar
-    length: 255
 source:
-  plugin: drupal6_user_role
+  plugin: d6_user_role
 process:
   id:
     -
@@ -19,20 +10,13 @@ process:
       plugin: dedupe_entity
       entity_type: user_role
       field: id
-  label: name
-# permissions start as array(array('perm' => array('perm1', 'perm2'))), array('perm' => array('perm3', 'perm4')))
-  permissions:
-    # extract gets array('perm' => array('perm1', 'perm2')) first
     -
-      plugin: extract
-      source: permissions
-      index:
-        - perm
-    # the pipeline is now array(array('perm1', 'perm2'))
-    - plugin: flatten
-    # the pipeline is now array('perm1', 'perm2')
+      plugin: user_update_8002
+  label: name
+  permissions:
     -
       plugin: static_map
+      source: permissions
       bypass: true
       map:
         'use PHP for block visibility': 'use PHP for settings'
@@ -50,6 +34,6 @@ process:
     - plugin: system_update_7000
     - plugin: node_update_7008
     - plugin: flatten
+    - plugin: filter_format_permission
 destination:
-  plugin: entity
-  entity_type: user_role
+  plugin: entity:user_role
diff --git a/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Plugin/migrate/source/d6/Role.php b/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Plugin/migrate/source/d6/Role.php
index b22765b..1677e33 100644
--- a/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Plugin/migrate/source/d6/Role.php
+++ b/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Plugin/migrate/source/d6/Role.php
@@ -9,13 +9,23 @@
 
 
 use Drupal\migrate\Row;
+use Drupal\migrate_drupal\Plugin\migrate\source\DrupalSqlBase;
 
 /**
  * Drupal 6 role source from database.
  *
- * @PluginId("drupal6_user_role")
+ * @MigrateSource(
+ *   id = "d6_user_role"
+ * )
  */
-class Role extends Drupal6SqlBase {
+class Role extends DrupalSqlBase {
+
+  /**
+   * List of filter IDs per role IDs.
+   *
+   * @var array
+   */
+  protected $filterPermissions = array();
 
   /**
    * {@inheritdoc}
@@ -32,31 +42,51 @@ public function query() {
    */
   public function fields() {
     return array(
-      'rid' => t('Role ID.'),
-      'name' => t('The name of the user role.'),
+      'rid' => $this->t('Role ID.'),
+      'name' => $this->t('The name of the user role.'),
     );
   }
 
   /**
    * {@inheritdoc}
    */
-  function prepareRow(Row $row, $keep = TRUE) {
-    $permissions = array();
-    $results = $this->database
-      ->select('permission', 'p', array('fetch' => \PDO::FETCH_ASSOC))
-      ->fields('p', array('pid', 'rid', 'perm', 'tid'))
-      ->condition('rid', $row->getSourceProperty('rid'))
-      ->execute();
-    foreach ($results as $perm) {
-      $permissions[] = array(
-        'pid' => $perm['pid'],
-        'rid' => $perm['rid'],
-        'perm' => array_map('trim', explode(',', $perm['perm'])),
-        'tid' => $perm['tid'],
-      );
+  protected function runQuery() {
+    $filter_roles = $this->select('filter_formats', 'f')
+      ->fields('f', array('format', 'roles'))
+      ->execute()
+      ->fetchAllKeyed();
+    foreach ($filter_roles as $format => $roles) {
+      // Drupal 6 code: $roles = ','. implode(',', $roles) .',';
+      // Remove the beginning and ending comma.
+      foreach (explode(',', trim($roles, ',')) as $rid) {
+        $this->filterPermissions[$rid][] = $format;
+      }
+    }
+    return parent::runQuery();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function prepareRow(Row $row, $keep = TRUE) {
+    $rid = $row->getSourceProperty('rid');
+    $permissions = $this->select('permission', 'p')
+      ->fields('p', array('perm'))
+      ->condition('rid', $rid)
+      ->execute()
+      ->fetchField();
+    $row->setSourceProperty('permissions', explode(', ', $permissions));
+    if (isset($this->filterPermissions[$rid])) {
+      $row->setSourceProperty("filter_permissions:$rid", $this->filterPermissions[$rid]);
     }
-    $row->setSourceProperty('permissions', $permissions);
     return parent::prepareRow($row);
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public function getIds() {
+    $ids['rid']['type'] = 'integer';
+    return $ids;
+  }
 }
diff --git a/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6ActionSettings.php b/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6ActionSettings.php
index 245d19e..587a84f 100644
--- a/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6ActionSettings.php
+++ b/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6ActionSettings.php
@@ -7,22 +7,17 @@
 
 namespace Drupal\migrate_drupal\Tests\Dump;
 
-use Drupal\Core\Database\Connection;
-
 /**
  * Database dump for testing action.settings.yml migration.
  */
-class Drupal6ActionSettings {
+class Drupal6ActionSettings extends Drupal6DumpBase {
 
   /**
-   * Sample database schema and values.
-   *
-   * @param \Drupal\Core\Database\Connection $database
-   *   The database connection.
+   * {@inheritdoc}
    */
-  public static function load(Connection $database) {
-    Drupal6DumpCommon::createVariable($database);
-    $database->insert('variable')->fields(array(
+  public function load() {
+    $this->createTable('variable');
+    $this->database->insert('variable')->fields(array(
       'name',
       'value',
     ))
diff --git a/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6AggregatorSettings.php b/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6AggregatorSettings.php
index 7d0de49..51bfb9f 100644
--- a/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6AggregatorSettings.php
+++ b/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6AggregatorSettings.php
@@ -7,22 +7,17 @@
 
 namespace Drupal\migrate_drupal\Tests\Dump;
 
-use Drupal\Core\Database\Connection;
-
 /**
  * Database dump for testing aggregator.settings.yml migration.
  */
-class Drupal6AggregatorSettings {
+class Drupal6AggregatorSettings extends Drupal6DumpBase {
 
   /**
-   * Sample database schema and values.
-   *
-   * @param \Drupal\Core\Database\Connection $database
-   *   The database connection.
+   * {@inheritdoc}
    */
-  public static function load(Connection $database) {
-    Drupal6DumpCommon::createVariable($database);
-    $database->insert('variable')->fields(array(
+  public function load() {
+    $this->createTable('variable');
+    $this->database->insert('variable')->fields(array(
       'name',
       'value',
     ))
diff --git a/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6BookSettings.php b/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6BookSettings.php
index 104fb7b..0bf6a57 100644
--- a/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6BookSettings.php
+++ b/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6BookSettings.php
@@ -7,22 +7,17 @@
 
 namespace Drupal\migrate_drupal\Tests\Dump;
 
-use Drupal\Core\Database\Connection;
-
 /**
  * Database dump for testing book.settings.yml migration.
  */
-class Drupal6BookSettings {
+class Drupal6BookSettings extends Drupal6DumpBase {
 
   /**
-   * Sample database schema and values.
-   *
-   * @param \Drupal\Core\Database\Connection $database
-   *   The database connection.
+   * {@inheritdoc}
    */
-  public static function load(Connection $database) {
-    Drupal6DumpCommon::createVariable($database);
-    $database->insert('variable')->fields(array(
+  public function load() {
+    $this->createTable('variable');
+    $this->database->insert('variable')->fields(array(
       'name',
       'value',
     ))
diff --git a/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6ContactSettings.php b/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6ContactSettings.php
index 4c16b44..56fddf5 100644
--- a/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6ContactSettings.php
+++ b/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6ContactSettings.php
@@ -7,22 +7,17 @@
 
 namespace Drupal\migrate_drupal\Tests\Dump;
 
-use Drupal\Core\Database\Connection;
-
 /**
  * Database dump for testing contact.settings.yml migration.
  */
-class Drupal6ContactSettings {
+class Drupal6ContactSettings extends Drupal6DumpBase {
 
   /**
-   * Sample database schema and values.
-   *
-   * @param \Drupal\Core\Database\Connection $database
-   *   The database connection.
+   * {@inheritdoc}
    */
-  public static function load(Connection $database) {
-    Drupal6DumpCommon::createVariable($database);
-    $database->insert('variable')->fields(array(
+  public function load() {
+    $this->createTable('variable');
+    $this->database->insert('variable')->fields(array(
       'name',
       'value',
     ))
diff --git a/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6DblogSettings.php b/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6DblogSettings.php
index 676dab9..2b04e9b 100644
--- a/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6DblogSettings.php
+++ b/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6DblogSettings.php
@@ -7,22 +7,17 @@
 
 namespace Drupal\migrate_drupal\Tests\Dump;
 
-use Drupal\Core\Database\Connection;
-
 /**
  * Database dump for testing dblog.settings.yml migration.
  */
-class Drupal6DblogSettings {
+class Drupal6DblogSettings extends Drupal6DumpBase {
 
   /**
-   * Sample database schema and values.
-   *
-   * @param \Drupal\Core\Database\Connection $database
-   *   The database connection.
+   * {@inheritdoc}
    */
-  public static function load(Connection $database) {
-    Drupal6DumpCommon::createVariable($database);
-    $database->insert('variable')->fields(array(
+  public function load() {
+    $this->createTable('variable');
+    $this->database->insert('variable')->fields(array(
       'name',
       'value',
     ))
diff --git a/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6FieldSettings.php b/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6FieldSettings.php
index 4425d5c..44e899f 100644
--- a/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6FieldSettings.php
+++ b/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6FieldSettings.php
@@ -7,28 +7,23 @@
 
 namespace Drupal\migrate_drupal\Tests\Dump;
 
-use Drupal\Core\Database\Connection;
-
 /**
  * Database dump for testing field.settings.yml migration.
  */
-class Drupal6FieldSettings {
+class Drupal6FieldSettings extends Drupal6DumpBase {
 
   /**
-   * Sample database schema and values.
-   *
-   * @param \Drupal\Core\Database\Connection $database
-   *   The database connection.
+   * {@inheritdoc}
    */
-  public static function load(Connection $database) {
-    Drupal6DumpCommon::createVariable($database);
-    $database->insert('variable')->fields(array(
+  public function load() {
+    $this->createTable('variable');
+    $this->database->insert('variable')->fields(array(
       'name',
       'value',
     ))
     ->values(array(
       'name' => 'field_language_fallback',
-        'value' => 'b:1;',
+      'value' => 'b:1;',
     ))
     ->execute();
   }
diff --git a/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6FileSettings.php b/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6FileSettings.php
index 61a1209..b00c541 100644
--- a/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6FileSettings.php
+++ b/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6FileSettings.php
@@ -7,22 +7,17 @@
 
 namespace Drupal\migrate_drupal\Tests\Dump;
 
-use Drupal\Core\Database\Connection;
-
 /**
  * Database dump for testing file.settings.yml migration.
  */
-class Drupal6FileSettings {
+class Drupal6FileSettings extends Drupal6DumpBase {
 
   /**
-   * Sample database schema and values.
-   *
-   * @param \Drupal\Core\Database\Connection $database
-   *   The database connection.
+   * {@inheritdoc}
    */
-  public static function load(Connection $database) {
-    Drupal6DumpCommon::createVariable($database);
-    $database->insert('variable')->fields(array(
+  public function load() {
+    $this->createTable('variable');
+    $this->database->insert('variable')->fields(array(
       'name',
       'value',
     ))
diff --git a/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6ForumSettings.php b/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6ForumSettings.php
index d75700e..8ae739e 100644
--- a/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6ForumSettings.php
+++ b/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6ForumSettings.php
@@ -7,22 +7,17 @@
 
 namespace Drupal\migrate_drupal\Tests\Dump;
 
-use Drupal\Core\Database\Connection;
-
 /**
  * Database dump for testing forum.site.yml migration.
  */
-class Drupal6ForumSettings {
+class Drupal6ForumSettings extends Drupal6DumpBase {
 
   /**
-   * Sample database schema and values.
-   *
-   * @param \Drupal\Core\Database\Connection $database
-   *   The database connection.
+   * {@inheritdoc}
    */
-  public static function load(Connection $database) {
-    Drupal6DumpCommon::createVariable($database);
-    $database->insert('variable')->fields(array(
+  public function load() {
+    $this->createTable('variable');
+    $this->database->insert('variable')->fields(array(
       'name',
       'value',
     ))
diff --git a/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6LocaleSettings.php b/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6LocaleSettings.php
index c32dedb..7dc6e5c 100644
--- a/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6LocaleSettings.php
+++ b/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6LocaleSettings.php
@@ -7,22 +7,17 @@
 
 namespace Drupal\migrate_drupal\Tests\Dump;
 
-use Drupal\Core\Database\Connection;
-
 /**
  * Database dump for testing locale.settings.yml migration.
  */
-class Drupal6LocaleSettings {
+class Drupal6LocaleSettings extends Drupal6DumpBase {
 
   /**
-   * Sample database schema and values.
-   *
-   * @param \Drupal\Core\Database\Connection $database
-   *   The database connection.
+   * {@inheritdoc}
    */
-  public static function load(Connection $database) {
-    Drupal6DumpCommon::createVariable($database);
-    $database->insert('variable')->fields(array(
+  public function load() {
+    $this->createTable('variable');
+    $this->database->insert('variable')->fields(array(
       'name',
       'value',
     ))
diff --git a/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6MenuSettings.php b/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6MenuSettings.php
index dc6fe2d..298b499 100644
--- a/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6MenuSettings.php
+++ b/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6MenuSettings.php
@@ -7,21 +7,18 @@
 
 namespace Drupal\migrate_drupal\Tests\Dump;
 
-use Drupal\Core\Database\Connection;
-
 /**
  * Database dump for testing menu.settings.yml migration.
  */
-class Drupal6MenuSettings {
+class Drupal6MenuSettings extends Drupal6DumpBase {
 
   /**
-   * Sample database schema and values.
-   *
-   * @param \Drupal\Core\Database\Connection $database
+   * {@inheritdoc}
    */
-  public static function load(Connection $database) {
-    Drupal6DumpCommon::createVariable($database);
-    $database->insert('variable')->fields(array(
+  public function load() {
+    $this->createTable('variable');
+    $this->setModuleVersion('menu', 6000);
+    $this->database->insert('variable')->fields(array(
       'name',
       'value',
     ))
diff --git a/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6NodeSettings.php b/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6NodeSettings.php
index d0af31a..4fb67b9 100644
--- a/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6NodeSettings.php
+++ b/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6NodeSettings.php
@@ -7,22 +7,17 @@
 
 namespace Drupal\migrate_drupal\Tests\Dump;
 
-use Drupal\Core\Database\Connection;
-
 /**
  * Database dump for testing node.settings.yml migration.
  */
-class Drupal6NodeSettings {
+class Drupal6NodeSettings extends Drupal6DumpBase {
 
   /**
-   * Sample database schema and values.
-   *
-   * @param \Drupal\Core\Database\Connection $database
-   *   The database connection.
+   * {@inheritdoc}
    */
-  public static function load(Connection $database) {
-    Drupal6DumpCommon::createVariable($database);
-    $database->insert('variable')->fields(array(
+  public function load() {
+    $this->createTable('variable');
+    $this->database->insert('variable')->fields(array(
       'name',
       'value',
     ))
diff --git a/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6SearchSettings.php b/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6SearchSettings.php
index 0b9d5af..fffc6c7 100644
--- a/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6SearchSettings.php
+++ b/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6SearchSettings.php
@@ -7,22 +7,17 @@
 
 namespace Drupal\migrate_drupal\Tests\Dump;
 
-use Drupal\Core\Database\Connection;
-
 /**
  * Database dump for testing forum.site.yml migration.
  */
-class Drupal6SearchSettings {
+class Drupal6SearchSettings extends Drupal6DumpBase {
 
   /**
-   * Mock the database schema and values.
-   *
-   * @param \Drupal\Core\Database\Connection $database
-   *   The mocked database connection.
+   * {@inheritdoc}
    */
-  public static function load(Connection $database) {
-    Drupal6DumpCommon::createVariable($database);
-    $database->insert('variable')->fields(array(
+  public function load() {
+    $this->createTable('variable');
+    $this->database->insert('variable')->fields(array(
       'name',
       'value',
     ))
diff --git a/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6SimpletestSettings.php b/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6SimpletestSettings.php
index 77f7c51..4469f8d 100644
--- a/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6SimpletestSettings.php
+++ b/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6SimpletestSettings.php
@@ -7,22 +7,17 @@
 
 namespace Drupal\migrate_drupal\Tests\Dump;
 
-use Drupal\Core\Database\Connection;
-
 /**
  * Database dump for testing simpletest.settings.yml migration.
  */
-class Drupal6SimpletestSettings {
+class Drupal6SimpletestSettings extends Drupal6DumpBase {
 
   /**
-   * Sample database schema and values.
-   *
-   * @param \Drupal\Core\Database\Connection $database
-   *   The database connection.
+   * {@inheritdoc}
    */
-  public static function load(Connection $database) {
-    Drupal6DumpCommon::createVariable($database);
-    $database->insert('variable')->fields(array(
+  public function load() {
+    $this->createTable('variable');
+    $this->database->insert('variable')->fields(array(
       'name',
       'value',
     ))
diff --git a/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6StatisticsSettings.php b/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6StatisticsSettings.php
index 573a5b4..1bec9c6 100644
--- a/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6StatisticsSettings.php
+++ b/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6StatisticsSettings.php
@@ -7,22 +7,17 @@
 
 namespace Drupal\migrate_drupal\Tests\Dump;
 
-use Drupal\Core\Database\Connection;
-
 /**
  * Database dump for testing statistics.settings.yml migration.
  */
-class Drupal6StatisticsSettings {
+class Drupal6StatisticsSettings extends Drupal6DumpBase {
 
   /**
-   * Sample database schema and values.
-   *
-   * @param \Drupal\Core\Database\Connection $database
-   *   The database connection.
+   * {@inheritdoc}
    */
-  public static function load(Connection $database) {
-    Drupal6DumpCommon::createVariable($database);
-    $database->insert('variable')->fields(array(
+  public function load() {
+    $this->createTable('variable');
+    $this->database->insert('variable')->fields(array(
       'name',
       'value',
     ))
diff --git a/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6SyslogSettings.php b/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6SyslogSettings.php
index ac0016b..4155820 100644
--- a/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6SyslogSettings.php
+++ b/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6SyslogSettings.php
@@ -7,22 +7,17 @@
 
 namespace Drupal\migrate_drupal\Tests\Dump;
 
-use Drupal\Core\Database\Connection;
-
 /**
  * Database dump for testing syslog.settings.yml migration.
  */
-class Drupal6SyslogSettings {
+class Drupal6SyslogSettings extends Drupal6DumpBase {
 
   /**
-   * Sample database schema and values.
-   *
-   * @param \Drupal\Core\Database\Connection $database
-   *   The database connection.
+   * {@inheritdoc}
    */
-  public static function load(Connection $database) {
-    Drupal6DumpCommon::createVariable($database);
-    $database->insert('variable')->fields(array(
+  public function load() {
+    $this->createTable('variable');
+    $this->database->insert('variable')->fields(array(
       'name',
       'value',
     ))
diff --git a/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6SystemCron.php b/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6SystemCron.php
index b08e904..44ee90b 100644
--- a/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6SystemCron.php
+++ b/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6SystemCron.php
@@ -7,22 +7,17 @@
 
 namespace Drupal\migrate_drupal\Tests\Dump;
 
-use Drupal\Core\Database\Connection;
-
 /**
  * Database dump for testing system.cron.yml migration.
  */
-class Drupal6SystemCron {
+class Drupal6SystemCron extends Drupal6DumpBase {
 
   /**
-   * Sample database schema and values.
-   *
-   * @param \Drupal\Core\Database\Connection $database
-   *   The database connection.
+   * {@inheritdoc}
    */
-  public static function load(Connection $database) {
-    Drupal6DumpCommon::createVariable($database);
-    $database->insert('variable')->fields(array(
+  public function load() {
+    $this->createTable('variable');
+    $this->database->insert('variable')->fields(array(
       'name',
       'value',
     ))
diff --git a/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6SystemFile.php b/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6SystemFile.php
index 14b8ee0..a3937a1 100644
--- a/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6SystemFile.php
+++ b/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6SystemFile.php
@@ -7,28 +7,24 @@
 
 namespace Drupal\migrate_drupal\Tests\Dump;
 
-use Drupal\Core\Database\Connection;
-
 /**
  * Database dump for testing system.file.yml migration.
  */
-class Drupal6SystemFile {
+class Drupal6SystemFile extends Drupal6DumpBase {
 
   /**
-   * Sample database schema and values.
-   *
-   * @param \Drupal\Core\Database\Connection $database
-   *   The database connection.
+   * {@inheritdoc}
    */
-  public static function load(Connection $database) {
-    Drupal6DumpCommon::createVariable($database);
-    $database->insert('variable')->fields(array(
+  public function load() {
+    $this->createTable('variable');
+    $this->database->insert('variable')->fields(array(
       'name',
       'value',
     ))
     ->values(array(
       'name' => 'file_directory_path',
-      'value' => 's:10:"files/test";',
+      // This sets up MigrateDrupal6Test to pass. Do not change.
+      'value' => 's:29:"core/modules/simpletest/files";',
     ))
     ->values(array(
       'name' => 'file_directory_temp',
@@ -37,4 +33,20 @@ public static function load(Connection $database) {
     ->execute();
   }
 
+  /**
+   * Dump for the standalone test in MigrateFileTest.
+   */
+  public function loadMigrateFileStandalone() {
+    $this->createTable('variable');
+    $this->database->insert('variable')->fields(array(
+      'name',
+      'value',
+    ))
+    ->values(array(
+      'name' => 'file_directory_path',
+      'value' => 's:10:"files/test";',
+    ))
+    ->execute();
+  }
+
 }
diff --git a/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6SystemFilter.php b/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6SystemFilter.php
index 22f0813..fe34217 100644
--- a/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6SystemFilter.php
+++ b/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6SystemFilter.php
@@ -7,22 +7,17 @@
 
 namespace Drupal\migrate_drupal\Tests\Dump;
 
-use Drupal\Core\Database\Connection;
-
 /**
  * Database dump for testing system.filter.yml migration.
  */
-class Drupal6SystemFilter {
+class Drupal6SystemFilter extends Drupal6DumpBase {
 
   /**
-   * Sample database schema and values.
-   *
-   * @param \Drupal\Core\Database\Connection $database
-   *   The database connection.
+   * {@inheritdoc}
    */
-  public static function load(Connection $database) {
-    Drupal6DumpCommon::createVariable($database);
-    $database->insert('variable')->fields(array(
+  public function load() {
+    $this->createTable('variable');
+    $this->database->insert('variable')->fields(array(
       'name',
       'value',
     ))
diff --git a/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6SystemImage.php b/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6SystemImage.php
index 90fd2f8..a5f0be9 100644
--- a/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6SystemImage.php
+++ b/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6SystemImage.php
@@ -7,22 +7,17 @@
 
 namespace Drupal\migrate_drupal\Tests\Dump;
 
-use Drupal\Core\Database\Connection;
-
 /**
  * Database dump for testing system.image.yml migration.
  */
-class Drupal6SystemImage {
+class Drupal6SystemImage extends Drupal6DumpBase {
 
   /**
-   * Sample database schema and values.
-   *
-   * @param \Drupal\Core\Database\Connection $database
-   *   The database connection.
+   * {@inheritdoc}
    */
-  public static function load(Connection $database) {
-    Drupal6DumpCommon::createVariable($database);
-    $database->insert('variable')->fields(array(
+  public function load() {
+    $this->createTable('variable');
+    $this->database->insert('variable')->fields(array(
       'name',
       'value',
     ))
diff --git a/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6SystemImageGd.php b/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6SystemImageGd.php
index a5b0875..f5798f1 100644
--- a/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6SystemImageGd.php
+++ b/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6SystemImageGd.php
@@ -7,22 +7,17 @@
 
 namespace Drupal\migrate_drupal\Tests\Dump;
 
-use Drupal\Core\Database\Connection;
-
 /**
  * Database dump for testing system.image.gd.yml migration.
  */
-class Drupal6SystemImageGd {
+class Drupal6SystemImageGd extends Drupal6DumpBase {
 
   /**
-   * Sample database schema and values.
-   *
-   * @param \Drupal\Core\Database\Connection $database
-   *   The database connection.
+   * {@inheritdoc}
    */
-  public static function load(Connection $database) {
-    Drupal6DumpCommon::createVariable($database);
-    $database->insert('variable')->fields(array(
+  public function load() {
+    $this->createTable('variable');
+    $this->database->insert('variable')->fields(array(
       'name',
       'value',
     ))
diff --git a/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6SystemMaintenance.php b/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6SystemMaintenance.php
index 8521f39..e98b741 100644
--- a/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6SystemMaintenance.php
+++ b/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6SystemMaintenance.php
@@ -7,22 +7,17 @@
 
 namespace Drupal\migrate_drupal\Tests\Dump;
 
-use Drupal\Core\Database\Connection;
-
 /**
  * Database dump for testing system.maintenance.yml migration.
  */
-class Drupal6SystemMaintenance {
+class Drupal6SystemMaintenance extends Drupal6DumpBase {
 
   /**
-   * Sample database schema and values.
-   *
-   * @param \Drupal\Core\Database\Connection $database
-   *   The database connection.
+   * {@inheritdoc}
    */
-  public static function load(Connection $database) {
-    Drupal6DumpCommon::createVariable($database);
-    $database->insert('variable')->fields(array(
+  public function load() {
+    $this->createTable('variable');
+    $this->database->insert('variable')->fields(array(
       'name',
       'value',
     ))
diff --git a/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6SystemPerformance.php b/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6SystemPerformance.php
index 0fd8153..b8bbf63 100644
--- a/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6SystemPerformance.php
+++ b/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6SystemPerformance.php
@@ -7,22 +7,17 @@
 
 namespace Drupal\migrate_drupal\Tests\Dump;
 
-use Drupal\Core\Database\Connection;
-
 /**
  * Database dump for testing system.performance.yml migration.
  */
-class Drupal6SystemPerformance {
+class Drupal6SystemPerformance extends Drupal6DumpBase {
 
   /**
-   * Sample database schema and values.
-   *
-   * @param \Drupal\Core\Database\Connection $database
-   *   The database connection.
+   * {@inheritdoc}
    */
-  public static function load(Connection $database) {
-    Drupal6DumpCommon::createVariable($database);
-    $database->insert('variable')->fields(array(
+  public function load() {
+    $this->createTable('variable');
+    $this->database->insert('variable')->fields(array(
       'name',
       'value',
     ))
diff --git a/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6SystemRss.php b/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6SystemRss.php
index 2090030..ecf7488 100644
--- a/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6SystemRss.php
+++ b/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6SystemRss.php
@@ -7,22 +7,17 @@
 
 namespace Drupal\migrate_drupal\Tests\Dump;
 
-use Drupal\Core\Database\Connection;
-
 /**
  * Database dump for testing system.settings.yml migration.
  */
-class Drupal6SystemRss {
+class Drupal6SystemRss extends Drupal6DumpBase {
 
   /**
-   * Sample database schema and values.
-   *
-   * @param \Drupal\Core\Database\Connection $database
-   *   The database connection.
+   * {@inheritdoc}
    */
-  public static function load(Connection $database) {
-    Drupal6DumpCommon::createVariable($database);
-    $database->insert('variable')->fields(array(
+  public function load() {
+    $this->createTable('variable');
+    $this->database->insert('variable')->fields(array(
       'name',
       'value',
     ))
diff --git a/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6SystemSite.php b/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6SystemSite.php
index 2310fb5..e6ebe16 100644
--- a/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6SystemSite.php
+++ b/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6SystemSite.php
@@ -7,22 +7,17 @@
 
 namespace Drupal\migrate_drupal\Tests\Dump;
 
-use Drupal\Core\Database\Connection;
-
 /**
  * Database dump for testing system.site.yml migration.
  */
-class Drupal6SystemSite {
+class Drupal6SystemSite extends Drupal6DumpBase {
 
   /**
-   * Sample database schema and values.
-   *
-   * @param \Drupal\Core\Database\Connection $database
-   *   The database connection.
+   * {@inheritdoc}
    */
-  public static function load(Connection $database) {
-    Drupal6DumpCommon::createVariable($database);
-    $database->insert('variable')->fields(array(
+  public function load() {
+    $this->createTable('variable');
+    $this->database->insert('variable')->fields(array(
       'name',
       'value',
     ))
@@ -36,7 +31,7 @@ public static function load(Connection $database) {
     ))
     ->values(array(
       'name' => 'site_slogan',
-      'value' => 's:13:"Migrate rocks";',
+      'value' => serialize('Migrate rocks'),
     ))
     ->values(array(
       'name' => 'site_frontpage',
@@ -44,7 +39,7 @@ public static function load(Connection $database) {
     ))
     ->values(array(
       'name' => 'site_403',
-      'value' => 's:4:"user";',
+      'value' => serialize('user'),
     ))
     ->values(array(
       'name' => 'site_404',
@@ -52,7 +47,7 @@ public static function load(Connection $database) {
     ))
     ->values(array(
       'name' => 'admin_compact_mode',
-      'value' => 'b:0;',
+      'value' => serialize(FALSE),
     ))
     ->execute();
   }
diff --git a/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6SystemTheme.php b/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6SystemTheme.php
index 4b015b5..9b9ceb3 100644
--- a/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6SystemTheme.php
+++ b/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6SystemTheme.php
@@ -7,22 +7,17 @@
 
 namespace Drupal\migrate_drupal\Tests\Dump;
 
-use Drupal\Core\Database\Connection;
-
 /**
  * Database dump for testing system.theme.yml migration.
  */
-class Drupal6SystemTheme {
+class Drupal6SystemTheme extends Drupal6DumpBase {
 
   /**
-   * Sample database schema and values.
-   *
-   * @param \Drupal\Core\Database\Connection $database
-   *   The database connection.
+   * {@inheritdoc}
    */
-  public static function load(Connection $database) {
-    Drupal6DumpCommon::createVariable($database);
-    $database->insert('variable')->fields(array(
+  public function load() {
+    $this->createTable('variable');
+    $this->database->insert('variable')->fields(array(
       'name',
       'value',
     ))
diff --git a/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6TaxonomySettings.php b/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6TaxonomySettings.php
index 9fc9d1a..25f45c0 100644
--- a/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6TaxonomySettings.php
+++ b/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6TaxonomySettings.php
@@ -7,22 +7,17 @@
 
 namespace Drupal\migrate_drupal\Tests\Dump;
 
-use Drupal\Core\Database\Connection;
-
 /**
  * Database dump for testing taxonomy.settings.yml migration.
  */
-class Drupal6TaxonomySettings {
+class Drupal6TaxonomySettings extends Drupal6DumpBase {
 
   /**
-   * Sample database schema and values.
-   *
-   * @param \Drupal\Core\Database\Connection $database
-   *   The database connection.
+   * {@inheritdoc}
    */
-  public static function load(Connection $database) {
-    Drupal6DumpCommon::createVariable($database);
-    $database->insert('variable')->fields(array(
+  public function load() {
+    $this->createTable('variable');
+    $this->database->insert('variable')->fields(array(
       'name',
       'value',
     ))
diff --git a/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6TextSettings.php b/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6TextSettings.php
index 02ba13a..59c7680 100644
--- a/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6TextSettings.php
+++ b/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6TextSettings.php
@@ -7,29 +7,20 @@
 
 namespace Drupal\migrate_drupal\Tests\Dump;
 
-use Drupal\Core\Database\Connection;
-
 /**
  * Database dump for testing text.settings.yml migration.
  */
-class Drupal6TextSettings {
+class Drupal6TextSettings extends Drupal6DumpBase {
 
   /**
-   * Sample database schema and values.
-   *
-   * @param \Drupal\Core\Database\Connection $database
-   *   The database connection.
+   * {@inheritdoc}
    */
-  public static function load(Connection $database) {
-    Drupal6DumpCommon::createVariable($database);
-    $database->insert('variable')->fields(array(
-      'name',
-      'value',
-    ))
-    ->values(array(
-      'name' => 'teaser_length',
-      'value' => 'i:600;',
-    ))
-    ->execute();
+  public function load() {
+    $this->createTable('variable');
+    // This needs to be a merge to avoid conflicts with Drupal6NodeBodyInstance.
+    $this->database->merge('variable')
+      ->key(array('name' => 'teaser_length'))
+      ->fields(array('value' => 'i:456;'))
+      ->execute();
   }
 }
diff --git a/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6UpdateSettings.php b/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6UpdateSettings.php
index 8198802..638b618 100644
--- a/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6UpdateSettings.php
+++ b/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6UpdateSettings.php
@@ -7,22 +7,17 @@
 
 namespace Drupal\migrate_drupal\Tests\Dump;
 
-use Drupal\Core\Database\Connection;
-
 /**
  * Database dump for testing update.settings.yml migration.
  */
-class Drupal6UpdateSettings {
+class Drupal6UpdateSettings extends Drupal6DumpBase {
 
   /**
-   * Sample database schema and values.
-   *
-   * @param \Drupal\Core\Database\Connection $database
-   *   The database connection.
+   * {@inheritdoc}
    */
-  public static function load(Connection $database) {
-    Drupal6DumpCommon::createVariable($database);
-    $database->insert('variable')->fields(array(
+  public function load() {
+    $this->createTable('variable');
+    $this->database->insert('variable')->fields(array(
       'name',
       'value',
     ))
diff --git a/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6UserMail.php b/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6UserMail.php
index 7784e74..114b482 100644
--- a/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6UserMail.php
+++ b/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6UserMail.php
@@ -7,22 +7,17 @@
 
 namespace Drupal\migrate_drupal\Tests\Dump;
 
-use Drupal\Core\Database\Connection;
-
 /**
  * Database dump for testing user.mail.yml migration.
  */
-class Drupal6UserMail {
+class Drupal6UserMail extends Drupal6DumpBase {
 
   /**
-   * Sample database schema and values.
-   *
-   * @param \Drupal\Core\Database\Connection $database
-   *   The database connection.
+   * {@inheritdoc}
    */
-  public static function load(Connection $database) {
-    Drupal6DumpCommon::createVariable($database);
-    $database->insert('variable')->fields(array(
+  public function load() {
+    $this->createTable('variable');
+    $this->database->insert('variable')->fields(array(
       'name',
       'value',
     ))
diff --git a/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6UserRole.php b/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6UserRole.php
index 934141e..12283bb 100644
--- a/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6UserRole.php
+++ b/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6UserRole.php
@@ -6,118 +6,121 @@
  */
 
 namespace Drupal\migrate_drupal\Tests\Dump;
-use Drupal\Core\Database\Connection;
-
 /**
  * Database dump for testing user role migration.
  */
-class Drupal6UserRole {
+class Drupal6UserRole extends Drupal6DumpBase {
 
   /**
-   * @param \Drupal\Core\Database\Connection $database
+   * {@inheritdoc}
    */
-  public static function load(Connection $database) {
-    $database->schema()->createTable('permission', array(
-      'description' => 'Stores permissions for users.',
-      'fields' => array(
-        'pid' => array(
-          'type' => 'serial',
-          'not null' => TRUE,
-          'description' => 'Primary Key: Unique permission ID.',
-        ),
-        'rid' => array(
-          'type' => 'int',
-          'unsigned' => TRUE,
-          'not null' => TRUE,
-          'default' => 0,
-          'description' => 'The {role}.rid to which the permissions are assigned.',
-        ),
-        'perm' => array(
-          'type' => 'text',
-          'not null' => FALSE,
-          'size' => 'big',
-          'description' => 'List of permissions being assigned.',
-        ),
-        'tid' => array(
-          'type' => 'int',
-          'unsigned' => TRUE,
-          'not null' => TRUE,
-          'default' => 0,
-          'description' => 'Originally intended for taxonomy-based permissions, but never used.',
+  public function load() {
+    foreach (static::getSchema() as $table => $schema) {
+      // Create tables.
+      $this->createTable($table, $schema);
+
+      // Insert data.
+      $data = static::getData($table);
+      if ($data) {
+        $query = $this->database->insert($table)->fields(array_keys($data[0]));
+        foreach ($data as $record) {
+          $query->values($record);
+        }
+        $query->execute();
+      }
+    }
+  }
+
+  /**
+   * Defines schema for this database dump.
+   *
+   * @return array
+   *   Associative array having the structure as is returned by hook_schema().
+   */
+  protected static function getSchema() {
+    return array(
+      'permission' => array(
+        'description' => 'Stores permissions for users.',
+        'fields' => array(
+          'pid' => array(
+            'type' => 'serial',
+            'not null' => TRUE,
+            'description' => 'Primary Key: Unique permission ID.',
+          ),
+          'rid' => array(
+            'type' => 'int',
+            'unsigned' => TRUE,
+            'not null' => TRUE,
+            'default' => 0,
+            'description' => 'The {role}.rid to which the permissions are assigned.',
+          ),
+          'perm' => array(
+            'type' => 'text',
+            'not null' => FALSE,
+            'size' => 'big',
+            'description' => 'List of permissions being assigned.',
+          ),
+          'tid' => array(
+            'type' => 'int',
+            'unsigned' => TRUE,
+            'not null' => TRUE,
+            'default' => 0,
+            'description' => 'Originally intended for taxonomy-based permissions, but never used.',
+          ),
         ),
+        'primary key' => array('pid'),
+        'indexes' => array('rid' => array('rid')),
       ),
-      'primary key' => array('pid'),
-      'indexes' => array('rid' => array('rid')),
-    ));
-    $database->schema()->createTable('role', array(
-      'description' => 'Stores user roles.',
-      'fields' => array(
-        'rid' => array(
-          'type' => 'serial',
-          'unsigned' => TRUE,
-          'not null' => TRUE,
-          'description' => 'Primary Key: Unique role id.',
-        ),
-        'name' => array(
-          'type' => 'varchar',
-          'length' => 64,
-          'not null' => TRUE,
-          'default' => '',
-          'description' => 'Unique role name.',
+      'role' => array(
+        'description' => 'Stores user roles.',
+        'fields' => array(
+          'rid' => array(
+            'type' => 'serial',
+            'unsigned' => TRUE,
+            'not null' => TRUE,
+            'description' => 'Primary Key: Unique role id.',
+          ),
+          'name' => array(
+            'type' => 'varchar',
+            'length' => 64,
+            'not null' => TRUE,
+            'default' => '',
+            'description' => 'Unique role name.',
+          ),
         ),
+        'unique keys' => array('name' => array('name')),
+        'primary key' => array('rid'),
       ),
-      'unique keys' => array('name' => array('name')),
-      'primary key' => array('rid'),
-    ));
-    $database->schema()->createTable('users_roles', array(
-      'description' => 'Maps users to roles.',
-      'fields' => array(
-        'uid' => array(
-          'type' => 'int',
-          'unsigned' => TRUE,
-          'not null' => TRUE,
-          'default' => 0,
-          'description' => 'Primary Key: {users}.uid for user.',
-        ),
-        'rid' => array(
-          'type' => 'int',
-          'unsigned' => TRUE,
-          'not null' => TRUE,
-          'default' => 0,
-          'description' => 'Primary Key: {role}.rid for role.',
-        ),
+    );
+  }
+
+  /**
+   * Returns dump data from a specific table.
+   *
+   * @param string $table
+   *   The table name.
+   *
+   * @return array
+   *   Array of associative arrays each one having fields as keys.
+   */
+  public static function getData($table) {
+    $data = array(
+      'permission' => array(
+        array('pid' => 1, 'rid' => 1, 'perm' => 'migrate test anonymous permission'),
+        array('pid' => 2, 'rid' => 2, 'perm' => 'migrate test authenticated permission'),
+        array('pid' => 3, 'rid' => 3, 'perm' => 'migrate test role 1 test permission'),
+        array('pid' => 4, 'rid' => 4, 'perm' => 'migrate test role 2 test permission, use PHP for settings, administer contact forms, skip comment approval, edit own blog content, edit any blog content, delete own blog content, delete any blog content, create forum content, delete any forum content, delete own forum content, edit any forum content, edit own forum content, administer nodes'),
       ),
-      'primary key' => array('uid', 'rid'),
-      'indexes' => array(
-        'rid' => array('rid'),
+      'role' => array(
+        array('rid' => 1, 'name' => 'anonymous user'),
+        array('rid' => 2, 'name' => 'authenticated user'),
+        array('rid' => 3, 'name' => 'migrate test role 1'),
+        array('rid' => 4, 'name' => 'migrate test role 2'),
+        array('rid' => 5, 'name' => 'migrate test role 3'),
       ),
-    ));
-    $database->insert('permission')->fields(array('pid', 'rid', 'perm'))
-      ->values(array('pid' => 3, 'rid' => 3, 'perm' => 'migrate test role 1 test permission'))
-      ->values(array('pid' => 4, 'rid' => 4, 'perm' => 'migrate test role 2 test permission'))
-      ->values(array('pid' => 5, 'rid' => 4, 'perm' => 'use PHP for settings'))
-      ->values(array('pid' => 6, 'rid' => 4, 'perm' => 'administer contact forms'))
-      ->values(array('pid' => 7, 'rid' => 4, 'perm' => 'skip comment approval'))
-      ->values(array('pid' => 8, 'rid' => 4, 'perm' => 'edit own blog content'))
-      ->values(array('pid' => 9, 'rid' => 4, 'perm' => 'edit any blog content'))
-      ->values(array('pid' => 10, 'rid' => 4, 'perm' => 'delete own blog content'))
-      ->values(array('pid' => 11, 'rid' => 4, 'perm' => 'delete any blog content'))
-      ->values(array('pid' => 12, 'rid' => 4, 'perm' => 'create forum content'))
-      ->values(array('pid' => 13, 'rid' => 4, 'perm' => 'delete any forum content'))
-      ->values(array('pid' => 14, 'rid' => 4, 'perm' => 'delete own forum content'))
-      ->values(array('pid' => 15, 'rid' => 4, 'perm' => 'edit any forum content'))
-      ->values(array('pid' => 16, 'rid' => 4, 'perm' => 'edit own forum content'))
-      ->values(array('pid' => 17, 'rid' => 4, 'perm' => 'administer nodes'))
-      ->execute();
-    $database->insert('role')->fields(array('rid', 'name'))
-      ->values(array('rid' => 3, 'name' => 'migrate test role 1'))
-      ->values(array('rid' => 4, 'name' => 'migrate test role 2'))
-      ->values(array('rid' => 5, 'name' => 'migrate test role 3'))
-      ->execute();
-    $database->insert('users_roles')->fields(array('uid', 'rid'))
-      ->values(array('uid' => 1, 'rid' => 3))
-      ->values(array('uid' => 1, 'rid' => 4))
-      ->execute();
+    );
+
+    return isset($data[$table]) ? $data[$table] : FALSE;
   }
 
 }
diff --git a/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/MigrateDrupalTestBase.php b/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/MigrateDrupalTestBase.php
index 370351c..7a6579c 100644
--- a/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/MigrateDrupalTestBase.php
+++ b/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/MigrateDrupalTestBase.php
@@ -11,5 +11,10 @@
 
 class MigrateDrupalTestBase extends MigrateTestBase {
 
+  /**
+   * Modules to enable.
+   *
+   * @var array
+   */
   public static $modules = array('migrate_drupal');
 }
diff --git a/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/d6/MigrateActionConfigsTest.php b/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/d6/MigrateActionConfigsTest.php
index ec3f29f..0d15565 100644
--- a/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/d6/MigrateActionConfigsTest.php
+++ b/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/d6/MigrateActionConfigsTest.php
@@ -7,7 +7,6 @@
 
 namespace Drupal\migrate_drupal\Tests\d6;
 
-use Drupal\migrate\MigrateMessage;
 use Drupal\migrate\MigrateExecutable;
 use Drupal\migrate_drupal\Tests\MigrateDrupalTestBase;
 
@@ -35,16 +34,23 @@ public static function getInfo() {
   }
 
   /**
-   * Tests migration of action variables to action.settings.yml.
+   * {@inheritdoc}
    */
-  public function testActionSettings() {
+  public function setUp() {
+    parent::setUp();
     $migration = entity_load('migration', 'd6_action_settings');
     $dumps = array(
       drupal_get_path('module', 'migrate_drupal') . '/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6ActionSettings.php',
     );
     $this->prepare($migration, $dumps);
-    $executable = new MigrateExecutable($migration, new MigrateMessage());
+    $executable = new MigrateExecutable($migration, $this);
     $executable->import();
+  }
+
+  /**
+   * Tests migration of action variables to action.settings.yml.
+   */
+  public function testActionSettings() {
     $config = \Drupal::config('action.settings');
     $this->assertIdentical($config->get('recursion_limit'), 35);
   }
diff --git a/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/d6/MigrateAggregatorConfigsTest.php b/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/d6/MigrateAggregatorConfigsTest.php
index 88ec847..4a13937 100644
--- a/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/d6/MigrateAggregatorConfigsTest.php
+++ b/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/d6/MigrateAggregatorConfigsTest.php
@@ -7,7 +7,6 @@
 
 namespace Drupal\migrate_drupal\Tests\d6;
 
-use Drupal\migrate\MigrateMessage;
 use Drupal\migrate\MigrateExecutable;
 use Drupal\migrate_drupal\Tests\MigrateDrupalTestBase;
 
@@ -35,16 +34,23 @@ public static function getInfo() {
   }
 
   /**
-   * Tests migration of aggregator variables to aggregator.settings.yml.
+   * {@inheritdoc}
    */
-  public function testAggregatorSettings() {
+  public function setUp() {
+    parent::setUp();
     $migration = entity_load('migration', 'd6_aggregator_settings');
     $dumps = array(
       drupal_get_path('module', 'migrate_drupal') . '/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6AggregatorSettings.php',
     );
     $this->prepare($migration, $dumps);
-    $executable = new MigrateExecutable($migration, new MigrateMessage());
+    $executable = new MigrateExecutable($migration, $this);
     $executable->import();
+  }
+
+  /**
+   * Tests migration of aggregator variables to aggregator.settings.yml.
+   */
+  public function testAggregatorSettings() {
     $config = \Drupal::config('aggregator.settings');
     $this->assertIdentical($config->get('fetcher'), 'aggregator');
     $this->assertIdentical($config->get('parser'), 'aggregator');
@@ -55,4 +61,5 @@ public function testAggregatorSettings() {
     $this->assertIdentical($config->get('source.list_max'), 3);
     $this->assertIdentical($config->get('source.category_selector'), 'checkboxes');
   }
+
 }
diff --git a/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/d6/MigrateBookConfigsTest.php b/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/d6/MigrateBookConfigsTest.php
index f3823e6..228b537 100644
--- a/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/d6/MigrateBookConfigsTest.php
+++ b/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/d6/MigrateBookConfigsTest.php
@@ -35,9 +35,10 @@ public static function getInfo() {
   }
 
   /**
-   * Tests migration of book variables to book.settings.yml.
+   * {@inheritdoc}
    */
-  public function testBookSettings() {
+  public function setUp() {
+    parent::setUp();
     $migration = entity_load('migration', 'd6_book_settings');
     $dumps = array(
       drupal_get_path('module', 'migrate_drupal') . '/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6BookSettings.php',
@@ -45,6 +46,12 @@ public function testBookSettings() {
     $this->prepare($migration, $dumps);
     $executable = new MigrateExecutable($migration, new MigrateMessage());
     $executable->import();
+  }
+
+  /**
+   * Tests migration of book variables to book.settings.yml.
+   */
+  public function testBookSettings() {
     $config = \Drupal::config('book.settings');
     $this->assertIdentical($config->get('child_type'), 'book');
     $this->assertIdentical($config->get('block.navigation.mode'), 'all pages');
diff --git a/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/d6/MigrateContactConfigsTest.php b/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/d6/MigrateContactConfigsTest.php
index 179b9e1..0c2790d 100644
--- a/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/d6/MigrateContactConfigsTest.php
+++ b/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/d6/MigrateContactConfigsTest.php
@@ -35,9 +35,10 @@ public static function getInfo() {
   }
 
   /**
-   * Tests migration of aggregator variables to aggregator.settings.yml.
+   * {@inheritdoc}
    */
-  public function testContactSettings() {
+  public function setUp() {
+    parent::setUp();
     $migration = entity_load('migration', 'd6_contact_settings');
     $dumps = array(
       drupal_get_path('module', 'migrate_drupal') . '/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6ContactSettings.php',
@@ -45,6 +46,12 @@ public function testContactSettings() {
     $this->prepare($migration, $dumps);
     $executable = new MigrateExecutable($migration, new MigrateMessage());
     $executable->import();
+  }
+
+  /**
+   * Tests migration of aggregator variables to aggregator.settings.yml.
+   */
+  public function testContactSettings() {
     $config = \Drupal::config('contact.settings');
     $this->assertIdentical($config->get('user_default_enabled'), true);
     $this->assertIdentical($config->get('flood.limit'), 3);
diff --git a/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/d6/MigrateDblogConfigsTest.php b/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/d6/MigrateDblogConfigsTest.php
index ecfa088..7bfda84 100644
--- a/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/d6/MigrateDblogConfigsTest.php
+++ b/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/d6/MigrateDblogConfigsTest.php
@@ -35,9 +35,10 @@ public static function getInfo() {
   }
 
   /**
-   * Tests migration of dblog variables to dblog.settings.yml.
+   * {@inheritdoc}
    */
-  public function testBookSettings() {
+  public function setUp() {
+    parent::setUp();
     $migration = entity_load('migration', 'd6_dblog_settings');
     $dumps = array(
       drupal_get_path('module', 'migrate_drupal') . '/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6DblogSettings.php',
@@ -45,6 +46,12 @@ public function testBookSettings() {
     $this->prepare($migration, $dumps);
     $executable = new MigrateExecutable($migration, new MigrateMessage());
     $executable->import();
+  }
+
+  /**
+   * Tests migration of dblog variables to dblog.settings.yml.
+   */
+  public function testBookSettings() {
     $config = \Drupal::config('dblog.settings');
     $this->assertIdentical($config->get('row_limit'), 1000);
   }
diff --git a/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/d6/MigrateFieldConfigsTest.php b/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/d6/MigrateFieldConfigsTest.php
index 0192130..d5647e3 100644
--- a/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/d6/MigrateFieldConfigsTest.php
+++ b/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/d6/MigrateFieldConfigsTest.php
@@ -7,7 +7,6 @@
 
 namespace Drupal\migrate_drupal\Tests\d6;
 
-use Drupal\migrate\MigrateMessage;
 use Drupal\migrate\MigrateExecutable;
 use Drupal\migrate_drupal\Tests\MigrateDrupalTestBase;
 
@@ -28,16 +27,23 @@ public static function getInfo() {
   }
 
   /**
-   * Tests migration of field variables to field.settings.yml.
+   * {@inheritdoc}
    */
-  public function testFieldSettings() {
+  public function setUp() {
+    parent::setUp();
     $migration = entity_load('migration', 'd6_field_settings');
     $dumps = array(
       drupal_get_path('module', 'migrate_drupal') . '/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6FieldSettings.php',
     );
     $this->prepare($migration, $dumps);
-    $executable = new MigrateExecutable($migration, new MigrateMessage());
+    $executable = new MigrateExecutable($migration, $this);
     $executable->import();
+  }
+
+  /**
+   * Tests migration of field variables to field.settings.yml.
+   */
+  public function testFieldSettings() {
     $config = \Drupal::config('field.settings');
     $this->assertIdentical($config->get('language_fallback'), TRUE);
   }
diff --git a/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/d6/MigrateFileConfigsTest.php b/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/d6/MigrateFileConfigsTest.php
index cb8d39c..e35fff9 100644
--- a/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/d6/MigrateFileConfigsTest.php
+++ b/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/d6/MigrateFileConfigsTest.php
@@ -35,9 +35,10 @@ public static function getInfo() {
   }
 
   /**
-   * Tests migration of file variables to file.settings.yml.
+   * {@inheritdoc}
    */
-  public function testFileSettings() {
+  public function setUp() {
+    parent::setUp();
     $migration = entity_load('migration', 'd6_file_settings');
     $dumps = array(
       drupal_get_path('module', 'migrate_drupal') . '/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6FileSettings.php',
@@ -45,6 +46,12 @@ public function testFileSettings() {
     $this->prepare($migration, $dumps);
     $executable = new MigrateExecutable($migration, new MigrateMessage());
     $executable->import();
+  }
+
+  /**
+   * Tests migration of file variables to file.settings.yml.
+   */
+  public function testFileSettings() {
     $config = \Drupal::config('file.settings');
     $this->assertIdentical($config->get('description.type'), 'textfield');
     $this->assertIdentical($config->get('description.length'), 128);
diff --git a/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/d6/MigrateForumConfigsTest.php b/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/d6/MigrateForumConfigsTest.php
index e5a2426..9c564f9 100644
--- a/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/d6/MigrateForumConfigsTest.php
+++ b/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/d6/MigrateForumConfigsTest.php
@@ -7,7 +7,6 @@
 
 namespace Drupal\migrate_drupal\Tests\d6;
 
-use Drupal\migrate\MigrateMessage;
 use Drupal\migrate\MigrateExecutable;
 use Drupal\migrate_drupal\Tests\MigrateDrupalTestBase;
 
@@ -35,16 +34,23 @@ public static function getInfo() {
   }
 
   /**
-   * Tests migration of forum variables to forum.settings.yml.
+   * {@inheritdoc}
    */
-  public function testForumSettings() {
+  public function setUp() {
+    parent::setUp();
     $migration = entity_load('migration', 'd6_forum_settings');
     $dumps = array(
       drupal_get_path('module', 'migrate_drupal') . '/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6ForumSettings.php',
     );
     $this->prepare($migration, $dumps);
-    $executable = new MigrateExecutable($migration, new MigrateMessage());
+    $executable = new MigrateExecutable($migration, $this);
     $executable->import();
+  }
+
+  /**
+   * Tests migration of forum variables to forum.settings.yml.
+   */
+  public function testForumSettings() {
     $config = \Drupal::config('forum.settings');
     $this->assertIdentical($config->get('topics.hot_threshold'), 15);
     $this->assertIdentical($config->get('topics.page_limit'), 25);
diff --git a/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/d6/MigrateLocaleConfigsTest.php b/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/d6/MigrateLocaleConfigsTest.php
index b47a0da..4c633e1 100644
--- a/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/d6/MigrateLocaleConfigsTest.php
+++ b/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/d6/MigrateLocaleConfigsTest.php
@@ -7,7 +7,6 @@
 
 namespace Drupal\migrate_drupal\Tests\d6;
 
-use Drupal\migrate\MigrateMessage;
 use Drupal\migrate\MigrateExecutable;
 use Drupal\migrate_drupal\Tests\MigrateDrupalTestBase;
 
@@ -35,16 +34,23 @@ public static function getInfo() {
   }
 
   /**
-   * Tests migration of locale variables to locale.settings.yml.
+   * {@inheritdoc}
    */
-  public function testLocaleSettings() {
+  public function setUp() {
+    parent::setUp();
     $migration = entity_load('migration', 'd6_locale_settings');
     $dumps = array(
       drupal_get_path('module', 'migrate_drupal') . '/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6LocaleSettings.php',
     );
     $this->prepare($migration, $dumps);
-    $executable = new MigrateExecutable($migration, new MigrateMessage());
+    $executable = new MigrateExecutable($migration, $this);
     $executable->import();
+  }
+
+  /**
+   * Tests migration of locale variables to locale.settings.yml.
+   */
+  public function testLocaleSettings() {
     $config = \Drupal::config('locale.settings');
     $this->assertIdentical($config->get('cache_string'), 1);
     $this->assertIdentical($config->get('javascript.directory'), 'languages');
diff --git a/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/d6/MigrateMenuConfigsTest.php b/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/d6/MigrateMenuConfigsTest.php
index ee96563..7e09ccb 100644
--- a/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/d6/MigrateMenuConfigsTest.php
+++ b/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/d6/MigrateMenuConfigsTest.php
@@ -7,7 +7,6 @@
 
 namespace Drupal\migrate_drupal\Tests\d6;
 
-use Drupal\migrate\MigrateMessage;
 use Drupal\migrate\MigrateExecutable;
 use Drupal\migrate_drupal\Tests\MigrateDrupalTestBase;
 
@@ -35,16 +34,23 @@ public static function getInfo() {
   }
 
   /**
-   * Tests migration of forum variables to forum.settings.yml.
+   * {@inheritdoc}
    */
-  public function testMenuSettings() {
+  public function setUp() {
+    parent::setUp();
     $migration = entity_load('migration', 'd6_menu_settings');
     $dumps = array(
       drupal_get_path('module', 'migrate_drupal') . '/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6MenuSettings.php',
     );
     $this->prepare($migration, $dumps);
-    $executable = new MigrateExecutable($migration, new MigrateMessage());
+    $executable = new MigrateExecutable($migration, $this);
     $executable->import();
+  }
+
+  /**
+   * Tests migration of variables for the menu module.
+   */
+  public function testMenuSettings() {
     $config = \Drupal::config('menu.settings');
     $this->assertIdentical($config->get('main_links'), 'primary-links');
     $this->assertIdentical($config->get('secondary_links'), 'secondary-links');
diff --git a/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/d6/MigrateNodeConfigsTest.php b/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/d6/MigrateNodeConfigsTest.php
index d24ed35..a20ba71 100644
--- a/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/d6/MigrateNodeConfigsTest.php
+++ b/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/d6/MigrateNodeConfigsTest.php
@@ -11,6 +11,9 @@
 use Drupal\migrate\MigrateExecutable;
 use Drupal\migrate_drupal\Tests\MigrateDrupalTestBase;
 
+/**
+ * Tests Drupal 6 node settings to Drupal 8 migration.
+ */
 class MigrateNodeConfigsTest extends MigrateDrupalTestBase {
 
   /**
@@ -31,7 +34,11 @@ public static function getInfo() {
     );
   }
 
-  function testNodeSettings() {
+  /**
+   * {@inheritdoc}
+   */
+  public function setUp() {
+    parent::setUp();
     $migration = entity_load('migration', 'd6_node_settings');
     $dumps = array(
       drupal_get_path('module', 'migrate_drupal') . '/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6NodeSettings.php',
@@ -39,6 +46,12 @@ function testNodeSettings() {
     $this->prepare($migration, $dumps);
     $executable = new MigrateExecutable($migration, new MigrateMessage);
     $executable->import();
+  }
+
+  /**
+   * Tests Drupal 6 node settings to Drupal 8 migration.
+   */
+  public function testNodeSettings() {
     $config = \Drupal::config('node.settings');
     $this->assertIdentical($config->get('use_admin_theme'), false);
   }
diff --git a/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/d6/MigrateSearchConfigsTest.php b/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/d6/MigrateSearchConfigsTest.php
index ae05722..f1b86bd 100644
--- a/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/d6/MigrateSearchConfigsTest.php
+++ b/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/d6/MigrateSearchConfigsTest.php
@@ -30,14 +30,15 @@ public static function getInfo() {
     return array(
       'name'  => 'Migrate variables to search.settings.yml',
       'description'  => 'Upgrade variables to search.settings.yml',
-      'group' => 'Migrate',
+      'group' => 'Migrate Drupal',
     );
   }
 
   /**
-   * Tests migration of search variables to search.settings.yml.
+   * {@inheritdoc}
    */
-  public function testSearchSettings() {
+  protected function setUp() {
+    parent::setUp();
     $migration = entity_load('migration', 'd6_search_settings');
     $dumps = array(
       drupal_get_path('module', 'migrate_drupal') . '/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6SearchSettings.php',
@@ -45,6 +46,12 @@ public function testSearchSettings() {
     $this->prepare($migration, $dumps);
     $executable = new MigrateExecutable($migration, new MigrateMessage());
     $executable->import();
+  }
+
+  /**
+   * Tests migration of search variables to search.settings.yml.
+   */
+  public function testSearchSettings() {
     $config = \Drupal::config('search.settings');
     $this->assertIdentical($config->get('index.minimum_word_size'), 3);
     $this->assertIdentical($config->get('index.overlap_cjk'), TRUE);
diff --git a/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/d6/MigrateSimpletestConfigsTest.php b/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/d6/MigrateSimpletestConfigsTest.php
index ca88209..ab58367 100644
--- a/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/d6/MigrateSimpletestConfigsTest.php
+++ b/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/d6/MigrateSimpletestConfigsTest.php
@@ -35,9 +35,10 @@ public static function getInfo() {
   }
 
   /**
-   * Tests migration of simpletest variables to simpletest.settings.yml.
+   * {@inheritdoc}
    */
-  public function testSimpletestSettings() {
+  protected function setUp() {
+    parent::setUp();
     $migration = entity_load('migration', 'd6_simpletest_settings');
     $dumps = array(
       drupal_get_path('module', 'migrate_drupal') . '/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6SimpletestSettings.php',
@@ -45,6 +46,12 @@ public function testSimpletestSettings() {
     $this->prepare($migration, $dumps);
     $executable = new MigrateExecutable($migration, new MigrateMessage());
     $executable->import();
+  }
+
+  /**
+   * Tests migration of simpletest variables to simpletest.settings.yml.
+   */
+  public function testSimpletestSettings() {
     $config = \Drupal::config('simpletest.settings');
     $this->assertIdentical($config->get('clear_results'), TRUE);
     $this->assertIdentical($config->get('httpauth.method'), CURLAUTH_BASIC);
diff --git a/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/d6/MigrateStatisticsConfigsTest.php b/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/d6/MigrateStatisticsConfigsTest.php
index 44ae47b..c1c9e7d 100644
--- a/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/d6/MigrateStatisticsConfigsTest.php
+++ b/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/d6/MigrateStatisticsConfigsTest.php
@@ -35,9 +35,10 @@ public static function getInfo() {
   }
 
   /**
-   * Tests migration of statistics variables to statistics.settings.yml.
+   * {@inheritdoc}
    */
-  public function testStatisticsSettings() {
+  protected function setUp() {
+    parent::setUp();
     $migration = entity_load('migration', 'd6_statistics_settings');
     $dumps = array(
       drupal_get_path('module', 'migrate_drupal') . '/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6StatisticsSettings.php',
@@ -45,6 +46,12 @@ public function testStatisticsSettings() {
     $this->prepare($migration, $dumps);
     $executable = new MigrateExecutable($migration, new MigrateMessage());
     $executable->import();
+  }
+
+  /**
+   * Tests migration of statistics variables to statistics.settings.yml.
+   */
+  public function testStatisticsSettings() {
     $config = \Drupal::config('statistics.settings');
     $this->assertIdentical($config->get('access_log.enable'), 0);
     $this->assertIdentical($config->get('access_log.max_lifetime'), 259200);
diff --git a/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/d6/MigrateSyslogConfigsTest.php b/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/d6/MigrateSyslogConfigsTest.php
index 47546f2..971cf87 100644
--- a/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/d6/MigrateSyslogConfigsTest.php
+++ b/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/d6/MigrateSyslogConfigsTest.php
@@ -7,7 +7,6 @@
 
 namespace Drupal\migrate_drupal\Tests\d6;
 
-use Drupal\migrate\MigrateMessage;
 use Drupal\migrate\MigrateExecutable;
 use Drupal\migrate_drupal\Tests\MigrateDrupalTestBase;
 
@@ -35,19 +34,25 @@ public static function getInfo() {
   }
 
   /**
-   * Tests migration of syslog variables to syslog.settings.yml.
+   * {@inheritdoc}
    */
-  public function testSyslogSettings() {
+  protected function setUp() {
+    parent::setUp();
     $migration = entity_load('migration', 'd6_syslog_settings');
     $dumps = array(
       drupal_get_path('module', 'migrate_drupal') . '/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6SyslogSettings.php',
     );
     $this->prepare($migration, $dumps);
-    $executable = new MigrateExecutable($migration, new MigrateMessage());
+    $executable = new MigrateExecutable($migration, $this);
     $executable->import();
+  }
+
+  /**
+   * Tests migration of syslog variables to syslog.settings.yml.
+   */
+  public function testSyslogSettings() {
     $config = \Drupal::config('syslog.settings');
     $this->assertIdentical($config->get('identity'), 'drupal');
-    // @TODO: change this to integer once there's schema of this config.
     $this->assertIdentical($config->get('facility'), '128');
   }
 }
diff --git a/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/d6/MigrateTaxonomyConfigsTest.php b/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/d6/MigrateTaxonomyConfigsTest.php
index 4cedef4..4a6b7d6 100644
--- a/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/d6/MigrateTaxonomyConfigsTest.php
+++ b/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/d6/MigrateTaxonomyConfigsTest.php
@@ -7,7 +7,6 @@
 
 namespace Drupal\migrate_drupal\Tests\d6;
 
-use Drupal\migrate\MigrateMessage;
 use Drupal\migrate\MigrateExecutable;
 use Drupal\migrate_drupal\Tests\MigrateDrupalTestBase;
 
@@ -35,16 +34,23 @@ public static function getInfo() {
   }
 
   /**
-   * Tests migration of taxonomy variables to taxonomy.settings.yml.
+   * {@inheritdoc}
    */
-  public function testTaxonomySettings() {
+  protected function setUp() {
+    parent::setUp();
     $migration = entity_load('migration', 'd6_taxonomy_settings');
     $dumps = array(
       drupal_get_path('module', 'migrate_drupal') . '/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6TaxonomySettings.php',
     );
     $this->prepare($migration, $dumps);
-    $executable = new MigrateExecutable($migration, new MigrateMessage());
+    $executable = new MigrateExecutable($migration, $this);
     $executable->import();
+  }
+
+  /**
+   * Tests migration of taxonomy variables to taxonomy.settings.yml.
+   */
+  public function testTaxonomySettings() {
     $config = \Drupal::config('taxonomy.settings');
     $this->assertIdentical($config->get('terms_per_page_admin'), 100);
     $this->assertIdentical($config->get('override_selector'), FALSE);
diff --git a/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/d6/MigrateTextConfigsTest.php b/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/d6/MigrateTextConfigsTest.php
index e47e99b..d33015e 100644
--- a/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/d6/MigrateTextConfigsTest.php
+++ b/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/d6/MigrateTextConfigsTest.php
@@ -7,7 +7,6 @@
 
 namespace Drupal\migrate_drupal\Tests\d6;
 
-use Drupal\migrate\MigrateMessage;
 use Drupal\migrate\MigrateExecutable;
 use Drupal\migrate_drupal\Tests\MigrateDrupalTestBase;
 
@@ -35,18 +34,25 @@ public static function getInfo() {
   }
 
   /**
-   * Tests migration of text variables to text.settings.yml.
+   * {@inheritdoc}
    */
-  public function testTextSettings() {
+  protected function setUp() {
+    parent::setUp();
     $migration = entity_load('migration', 'd6_text_settings');
     $dumps = array(
       drupal_get_path('module', 'migrate_drupal') . '/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6TextSettings.php',
     );
     $this->prepare($migration, $dumps);
-    $executable = new MigrateExecutable($migration, new MigrateMessage());
+    $executable = new MigrateExecutable($migration, $this);
     $executable->import();
+  }
+
+  /**
+   * Tests migration of text variables to text.settings.yml.
+   */
+  public function testTextSettings() {
     $config = \Drupal::config('text.settings');
-    $this->assertIdentical($config->get('default_summary_length'), 600);
+    $this->assertIdentical($config->get('default_summary_length'), 456);
   }
 
 }
diff --git a/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/d6/MigrateUpdateConfigsTest.php b/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/d6/MigrateUpdateConfigsTest.php
index f8721c5..c685edf 100644
--- a/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/d6/MigrateUpdateConfigsTest.php
+++ b/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/d6/MigrateUpdateConfigsTest.php
@@ -7,7 +7,6 @@
 
 namespace Drupal\migrate_drupal\Tests\d6;
 
-use Drupal\migrate\MigrateMessage;
 use Drupal\migrate\MigrateExecutable;
 use Drupal\migrate_drupal\Tests\MigrateDrupalTestBase;
 
@@ -35,16 +34,23 @@ public static function getInfo() {
   }
 
   /**
-   * Tests migration of update variables to update.settings.yml.
+   * {@inheritdoc}
    */
-  public function testUpdateSettings() {
+  protected function setUp() {
+    parent::setUp();
     $migration = entity_load('migration', 'd6_update_settings');
     $dumps = array(
       drupal_get_path('module', 'migrate_drupal') . '/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6UpdateSettings.php',
     );
     $this->prepare($migration, $dumps);
-    $executable = new MigrateExecutable($migration, new MigrateMessage());
+    $executable = new MigrateExecutable($migration, $this);
     $executable->import();
+  }
+
+  /**
+   * Tests migration of update variables to update.settings.yml.
+   */
+  public function testUpdateSettings() {
     $config = \Drupal::config('update.settings');
     $this->assertIdentical($config->get('fetch.max_attempts'), 2);
     $this->assertIdentical($config->get('fetch.url'), 'http://updates.drupal.org/release-history');
diff --git a/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/d6/MigrateUserConfigsTest.php b/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/d6/MigrateUserConfigsTest.php
index 3d35256..37211ea 100644
--- a/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/d6/MigrateUserConfigsTest.php
+++ b/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/d6/MigrateUserConfigsTest.php
@@ -7,7 +7,6 @@
 
 namespace Drupal\migrate_drupal\Tests\d6;
 
-use Drupal\migrate\MigrateMessage;
 use Drupal\migrate\MigrateExecutable;
 use Drupal\migrate_drupal\Tests\MigrateDrupalTestBase;
 
@@ -28,16 +27,23 @@ public static function getInfo() {
   }
 
   /**
-   * Tests migration of user variables to user.mail.yml.
+   * {@inheritdoc}
    */
-  public function testUserMail() {
+  protected function setUp() {
+    parent::setUp();
     $migration = entity_load('migration', 'd6_user_mail');
     $dumps = array(
       drupal_get_path('module', 'migrate_drupal') . '/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6UserMail.php',
     );
     $this->prepare($migration, $dumps);
-    $executable = new MigrateExecutable($migration, new MigrateMessage());
+    $executable = new MigrateExecutable($migration, $this);
     $executable->import();
+  }
+
+  /**
+   * Tests migration of user variables to user.mail.yml.
+   */
+  public function testUserMail() {
     $config = \Drupal::config('user.mail');
     $this->assertIdentical($config->get('status_activated.subject'), 'Account details for !username at !site (approved)');
     $this->assertIdentical($config->get('status_activated.body'), "!username,\n\nYour account at !site has been activated.\n\nYou may now log in by clicking on this link or copying and pasting it in your browser:\n\n!login_url\n\nThis is a one-time login, so it can be used only once.\n\nAfter logging in, you will be redirected to !edit_uri so you can change your password.\n\nOnce you have set your own password, you will be able to log in to !login_uri in the future using:\n\nusername: !username\n");
diff --git a/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/d6/MigrateUserRoleTest.php b/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/d6/MigrateUserRoleTest.php
index 19cabeb..ea3f7c2 100644
--- a/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/d6/MigrateUserRoleTest.php
+++ b/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/d6/MigrateUserRoleTest.php
@@ -8,11 +8,12 @@
 namespace Drupal\migrate_drupal\Tests\d6;
 
 use Drupal\migrate\MigrateExecutable;
-use Drupal\migrate\MigrateMessage;
 use Drupal\migrate_drupal\Tests\MigrateDrupalTestBase;
 
 class MigrateUserRoleTest extends MigrateDrupalTestBase {
 
+  static $modules = array('filter');
+
   /**
    * {@inheritdoc}
    */
@@ -24,20 +25,59 @@ public static function getInfo() {
     );
   }
 
-  function testUserRole() {
+  /**
+   * {@inheritdoc}
+   */
+  public function setUp() {
+    parent::setUp();
+    // We need some sample data so we can use the Migration process plugin.
+    $table_name = entity_load('migration', 'd6_filter_format')->getIdMap()->mapTableName();
+    db_insert($table_name)->fields(array(
+      'sourceid1',
+      'destid1',
+    ))
+    ->values(array(
+      'sourceid1' => 1,
+      'destid1' => 'filtered_html',
+    ))
+    ->values(array(
+      'sourceid1' => 2,
+      'destid1' => 'full_html',
+    ))
+    ->execute();
+
     /** @var \Drupal\migrate\entity\Migration $migration */
     $migration = entity_load('migration', 'd6_user_role');
+    $path = drupal_get_path('module', 'migrate_drupal');
     $dumps = array(
-      drupal_get_path('module', 'migrate_drupal') . '/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6UserRole.php',
+      $path . '/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6UserRole.php',
+      $path . '/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6FilterFormat.php',
     );
     $this->prepare($migration, $dumps);
-    $executable = new MigrateExecutable($migration, new MigrateMessage());
+    $executable = new MigrateExecutable($migration, $this);
     $executable->import();
+  }
 
+  /**
+   * Tests user role migration.
+   */
+  public function testUserRole() {
+    /** @var \Drupal\migrate\entity\Migration $migration */
+    $migration = entity_load('migration', 'd6_user_role');
+    $rid = 'anonymous';
+    $anonymous = entity_load('user_role', $rid);
+    $this->assertEqual($anonymous->id(), $rid);
+    $this->assertEqual($anonymous->getPermissions(), array('migrate test anonymous permission', 'use text format filtered_html'));
+    $this->assertEqual(array($rid), $migration->getIdMap()->lookupDestinationId(array(1)));
+    $rid = 'authenticated';
+    $authenticated = entity_load('user_role', $rid);
+    $this->assertEqual($authenticated->id(), $rid);
+    $this->assertEqual($authenticated->getPermissions(), array('migrate test authenticated permission', 'use text format filtered_html'));
+    $this->assertEqual(array($rid), $migration->getIdMap()->lookupDestinationId(array(2)));
     $rid = 'migrate_test_role_1';
     $migrate_test_role_1 = entity_load('user_role', $rid);
     $this->assertEqual($migrate_test_role_1->id(), $rid);
-    $this->assertEqual($migrate_test_role_1->getPermissions(), array(0 => 'migrate test role 1 test permission'));
+    $this->assertEqual($migrate_test_role_1->getPermissions(), array(0 => 'migrate test role 1 test permission', 'use text format full_html'));
     $this->assertEqual(array($rid), $migration->getIdMap()->lookupDestinationId(array(3)));
     $rid = 'migrate_test_role_2';
     $migrate_test_role_2 = entity_load('user_role', $rid);
diff --git a/core/modules/migrate_drupal/migrate_drupal.info.yml b/core/modules/migrate_drupal/migrate_drupal.info.yml
index 59fb9ae..a0bdaf6 100644
--- a/core/modules/migrate_drupal/migrate_drupal.info.yml
+++ b/core/modules/migrate_drupal/migrate_drupal.info.yml
@@ -4,3 +4,5 @@ description: 'Contains migrations from older Drupal versions.'
 package: Core
 version: VERSION
 core: 8.x
+dependencies:
+  - migrate
diff --git a/core/modules/migrate_drupal/migrate_drupal.module b/core/modules/migrate_drupal/migrate_drupal.module
index e69de29..726222d 100644
--- a/core/modules/migrate_drupal/migrate_drupal.module
+++ b/core/modules/migrate_drupal/migrate_drupal.module
@@ -0,0 +1,11 @@
+<?php
+
+/**
+ * Implements hook_entity_type_alter().
+ */
+function migrate_drupal_entity_type_alter(array &$entity_types) {
+  /** @var \Drupal\Core\Config\Entity\ConfigEntityType[] $entity_types */
+  $entity_types['migration']
+    ->setClass('Drupal\migrate_drupal\Entity\Migration')
+    ->setControllerClass('storage', 'Drupal\migrate_drupal\MigrationStorageController');
+}
diff --git a/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Entity/Migration.php b/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Entity/Migration.php
new file mode 100644
index 0000000..7875ddf
--- /dev/null
+++ b/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Entity/Migration.php
@@ -0,0 +1,38 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\migrate_drupal\Entity\Migration.
+ */
+
+namespace Drupal\migrate_drupal\Entity;
+
+use Drupal\migrate\Entity\Migration as BaseMigration;
+
+class Migration extends BaseMigration implements MigrationInterface {
+
+  /**
+   * The load plugin configuration, if any.
+   *
+   * @var array
+   */
+  public $load = array();
+
+  /**
+   * The load plugin.
+   *
+   * @var \Drupal\migrate_drupal\Plugin\MigrateLoadInterface|false
+   */
+  protected $loadPlugin = FALSE;
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getLoadPlugin() {
+    if ($this->load && !$this->loadPlugin) {
+      $this->loadPlugin = \Drupal::service('plugin.manager.migrate.load')->createInstance($this->load['plugin'], $this->load, $this);
+    }
+    return $this->loadPlugin;
+  }
+
+}
diff --git a/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Entity/MigrationInterface.php b/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Entity/MigrationInterface.php
new file mode 100644
index 0000000..e59631e
--- /dev/null
+++ b/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Entity/MigrationInterface.php
@@ -0,0 +1,20 @@
+<?php
+/**
+ * @file
+ * Contains
+ */
+
+namespace Drupal\migrate_drupal\Entity;
+
+use Drupal\migrate\Entity\MigrationInterface as BaseMigrationInterface;
+
+interface MigrationInterface extends BaseMigrationInterface {
+
+  /**
+   * Returns the initialized load plugin if there's one.
+   *
+   * @return \Drupal\migrate_drupal\Plugin\MigrateLoadInterface|false
+   */
+  public function getLoadPlugin();
+
+}
diff --git a/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/MigrationStorageController.php b/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/MigrationStorageController.php
new file mode 100644
index 0000000..08e5d63
--- /dev/null
+++ b/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/MigrationStorageController.php
@@ -0,0 +1,114 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\migrate_drupal\MigrateStorageController.
+ */
+
+namespace Drupal\migrate_drupal;
+
+use Drupal\Component\Utility\String;
+use Drupal\Core\Entity\EntityInterface;
+use Drupal\Core\Entity\EntityStorageException;
+use Drupal\migrate\MigrationStorageController as BaseMigrationStorageController;
+
+/**
+ * Storage controller for migration entities.
+ */
+class MigrationStorageController extends BaseMigrationStorageController {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function loadMultiple(array $ids = NULL) {
+    $ids_to_load = array();
+    $dynamic_ids = array();
+    if (isset($ids)) {
+      foreach ($ids as $id) {
+        // Evaluate whether or not this migration is dynamic in the form of
+        // migration_id:* to load all the additional migrations.
+        if (($n = strpos($id, ':')) !== FALSE) {
+          $base_id = substr($id, 0, $n);
+          $ids_to_load[] = $base_id;
+          // Get the ids of the additional migrations.
+          $sub_id = substr($id, $n + 1);
+          if ($sub_id == '*') {
+            // If the id of the additional migration is '*', get all of them.
+            $dynamic_ids[$base_id] = NULL;
+          }
+          elseif (!isset($dynamic_ids[$base_id]) || is_array($dynamic_ids[$base_id])) {
+            $dynamic_ids[$base_id][] = $sub_id;
+          }
+        }
+        else {
+          $ids_to_load[] = $id;
+        }
+      }
+      $ids = array_flip($ids);
+    }
+    else {
+      $ids_to_load = NULL;
+    }
+
+    /** @var \Drupal\migrate_drupal\Entity\MigrationInterface[] $entities */
+    $entities = parent::loadMultiple($ids_to_load);
+    if (!isset($ids)) {
+      // Changing the array being foreach()'d is not a good idea.
+      $return = array();
+      foreach ($entities as $entity_id => $entity) {
+        if ($plugin = $entity->getLoadPlugin()) {
+          $new_entities = $plugin->loadMultiple($this);
+          $this->getDynamicIds($dynamic_ids, $new_entities);
+          $return += $new_entities;
+        }
+        else {
+          $return[$entity_id] = $entity;
+        }
+      }
+      $entities = $return;
+    }
+    else {
+      foreach ($dynamic_ids as $base_id => $sub_ids) {
+        $entity = $entities[$base_id];
+        if ($plugin = $entity->getLoadPlugin()) {
+          unset($entities[$base_id]);
+          $new_entities = $plugin->loadMultiple($this, $sub_ids);
+          if (!isset($sub_ids)) {
+            unset($dynamic_ids[$base_id]);
+            $this->getDynamicIds($dynamic_ids, $new_entities);
+          }
+          $entities += $new_entities;
+        }
+      }
+    }
+
+    // Build an array of dependencies and set the order of the migrations.
+    return $this->buildDependencyMigration($entities, $dynamic_ids);
+  }
+
+  /**
+   * Extract the dynamic id mapping from entities loaded by plugin.
+   *
+   * @param array $dynamic_ids
+   *   Get the dynamic migration ids.
+   * @param array $entities
+   *   An array of entities.
+   */
+  protected function getDynamicIds(array &$dynamic_ids, array $entities) {
+    foreach (array_keys($entities) as $new_id) {
+      list($base_id, $sub_id) = explode(':', $new_id, 2);
+      $dynamic_ids[$base_id][] = $sub_id;
+    }
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function save(EntityInterface $entity) {
+    if (strpos($entity->id(), ':') !== FALSE) {
+      throw new EntityStorageException(String::format("Dynamic migration %id can't be saved", array('$%id' => $entity->id())));
+    }
+    return parent::save($entity);
+  }
+
+}
diff --git a/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Plugin/migrate/source/Variable.php b/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Plugin/migrate/source/Variable.php
new file mode 100644
index 0000000..0c3e8dc
--- /dev/null
+++ b/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Plugin/migrate/source/Variable.php
@@ -0,0 +1,70 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\migrate\Plugin\migrate\source\d6\Variable.
+ */
+
+namespace Drupal\migrate_drupal\Plugin\migrate\source;
+
+use Drupal\migrate\Entity\MigrationInterface;
+
+/**
+ * Drupal 6 variable source from database.
+ *
+ * This source class always returns a single row and as such is not a good
+ * example for any normal source class returning multiple rows.
+ *
+ * @MigrateSource(
+ *   id = "variable"
+ * )
+ */
+class Variable extends DrupalSqlBase {
+
+  /**
+   * The variable names to fetch.
+   *
+   * @var array
+   */
+  protected $variables;
+
+  /**
+   * {@inheritdoc}
+   */
+  public function __construct(array $configuration, $plugin_id, array $plugin_definition, MigrationInterface $migration) {
+    parent::__construct($configuration, $plugin_id, $plugin_definition, $migration);
+    $this->variables = $this->configuration['variables'];
+  }
+
+  protected function runQuery() {
+    return new \ArrayIterator(array(array_map('unserialize', $this->prepareQuery()->execute()->fetchAllKeyed())));
+  }
+
+  public function count() {
+    return intval($this->query()->countQuery()->execute()->fetchField() > 0);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function fields() {
+    return array_combine($this->variables, $this->variables);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function query() {
+    return $this->getDatabase()
+      ->select('variable', 'v')
+      ->fields('v', array('name', 'value'))
+      ->condition('name', $this->variables, 'IN');
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getIds() {
+    return array();
+  }
+}
diff --git a/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Plugin/migrate/source/d6/Variable.php b/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Plugin/migrate/source/d6/Variable.php
deleted file mode 100644
index e9a24b5..0000000
--- a/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Plugin/migrate/source/d6/Variable.php
+++ /dev/null
@@ -1,61 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\migrate\Plugin\migrate\source\d6\Variable.
- */
-
-namespace Drupal\migrate_drupal\Plugin\migrate\source\d6;
-
-use Drupal\migrate\Entity\MigrationInterface;
-
-/**
- * Drupal 6 variable source from database.
- *
- * This source class always returns a single row and as such is not a good
- * example for any normal source class returning multiple rows.
- *
- * @PluginID("drupal6_variable")
- */
-class Variable extends Drupal6SqlBase {
-
-  /**
-   * The variable names to fetch.
-   *
-   * @var array
-   */
-  protected $variables;
-
-  /**
-   * {@inheritdoc}
-   */
-  function __construct(array $configuration, $plugin_id, array $plugin_definition, MigrationInterface $migration) {
-    parent::__construct($configuration, $plugin_id, $plugin_definition, $migration);
-    $this->variables = $this->configuration['variables'];
-  }
-
-  protected function runQuery() {
-    return new \ArrayIterator(array(array_map('unserialize', $this->query()->execute()->fetchAllKeyed())));
-  }
-
-  public function count() {
-    return intval($this->query()->countQuery()->execute()->fetchField() > 0);
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function fields() {
-    return array_combine($this->variables, $this->variables);
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  function query() {
-    return $this->getDatabase()
-      ->select('variable', 'v')
-      ->fields('v', array('name', 'value'))
-      ->condition('name', $this->variables, 'IN');
-  }
-}
diff --git a/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6DumpBase.php b/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6DumpBase.php
new file mode 100644
index 0000000..c340f4c
--- /dev/null
+++ b/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6DumpBase.php
@@ -0,0 +1,251 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\migrate_drupal\Tests\Dump\Drupal6DumpBase.
+ */
+
+namespace Drupal\migrate_drupal\Tests\Dump;
+use Drupal\Core\Database\Connection;
+
+/**
+ * Base class for the dump classes.
+ */
+class Drupal6DumpBase {
+
+  /**
+   * The database connection.
+   *
+   * @var \Drupal\Core\Database\Connection
+   */
+  protected $database;
+
+  /**
+   * Sample database schema and values.
+   *
+   * @param \Drupal\Core\Database\Connection $database
+   *   The database connection.
+   */
+  public function __construct(Connection $database) {
+    $this->database = $database;
+  }
+
+  /**
+   * Create a new table from a Drupal table definition if it doesn't exist.
+   *
+   * @param $name
+   *   The name of the table to create.
+   * @param $table
+   *   A Schema API table definition array.
+   */
+  protected function createTable($name, $table = NULL) {
+    // This must be on the database connection to be shared among classes.
+    if (empty($this->database->migrateTables[$name])) {
+      $this->database->migrateTables[$name] = TRUE;
+      $this->database->schema()->createTable($name, $table ?: $this->tableDefinitions()[$name]);
+    }
+  }
+
+  /**
+   * Table definitions.
+   */
+  protected function tableDefinitions() {
+    return array(
+      'node_type' => array(
+        'description' => 'Stores information about all defined {node} types.',
+        'fields' => array(
+          'type' => array(
+            'description' => 'The machine-readable name of this type.',
+            'type' => 'varchar',
+            'length' => 32,
+            'not null' => TRUE),
+          'name' => array(
+            'description' => 'The human-readable name of this type.',
+            'type' => 'varchar',
+            'length' => 255,
+            'not null' => TRUE,
+            'default' => ''),
+          'module' => array(
+            'description' => 'The base string used to construct callbacks corresponding to this node type.',
+            'type' => 'varchar',
+            'length' => 255,
+            'not null' => TRUE),
+          'description'    => array(
+            'description' => 'A brief description of this type.',
+            'type' => 'text',
+            'not null' => TRUE,
+            'size' => 'medium'),
+          'help' => array(
+            'description' => 'Help information shown to the user when creating a {node} of this type.',
+            'type' => 'text',
+            'not null' => TRUE,
+            'size' => 'medium'),
+          'has_title' => array(
+            'description' => 'Boolean indicating whether this type uses the {node}.title field.',
+            'type' => 'int',
+            'unsigned' => TRUE,
+            'not null' => TRUE,
+            'size' => 'tiny'),
+          'title_label' => array(
+            'description' => 'The label displayed for the title field on the edit form.',
+            'type' => 'varchar',
+            'length' => 255,
+            'not null' => TRUE,
+            'default' => ''),
+          'has_body' => array(
+            'description' => 'Boolean indicating whether this type uses the {node_revisions}.body field.',
+            'type' => 'int',
+            'unsigned' => TRUE,
+            'not null' => TRUE,
+            'size' => 'tiny'),
+          'body_label' => array(
+            'description' => 'The label displayed for the body field on the edit form.',
+            'type' => 'varchar',
+            'length' => 255,
+            'not null' => TRUE,
+            'default' => ''),
+          'min_word_count' => array(
+            'description' => 'The minimum number of words the body must contain.',
+            'type' => 'int',
+            'unsigned' => TRUE,
+            'not null' => TRUE,
+            'size' => 'small'),
+          'custom' => array(
+            'description' => 'A boolean indicating whether this type is defined by a module (FALSE) or by a user via a module like the Content Construction Kit (TRUE).',
+            'type' => 'int',
+            'not null' => TRUE,
+            'default' => 0,
+            'size' => 'tiny'),
+          'modified' => array(
+            'description' => 'A boolean indicating whether this type has been modified by an administrator; currently not used in any way.',
+            'type' => 'int',
+            'not null' => TRUE,
+            'default' => 0,
+            'size' => 'tiny'),
+          'locked' => array(
+            'description' => 'A boolean indicating whether the administrator can change the machine name of this type.',
+            'type' => 'int',
+            'not null' => TRUE,
+            'default' => 0,
+            'size' => 'tiny'),
+          'orig_type' => array(
+            'description' => 'The original machine-readable name of this node type. This may be different from the current type name if the locked field is 0.',
+            'type' => 'varchar',
+            'length' => 255,
+            'not null' => TRUE,
+            'default' => '',
+          ),
+        ),
+        'primary key' => array('type'),
+      ),
+      'variable' => array(
+        'fields' => array(
+          'name' => array(
+            'type' => 'varchar',
+            'length' => 128,
+            'not null' => TRUE,
+            'default' => '',
+          ),
+          'value' => array(
+            'type' => 'blob',
+            'not null' => TRUE,
+            'size' => 'big',
+            'translatable' => TRUE,
+          ),
+        ),
+        'primary key' => array(
+          'name',
+        ),
+        'module' => 'book',
+        'name' => 'variable',
+      ),
+      'system' => array(
+        'description' => "A list of all modules, themes, and theme engines that are or have been installed in Drupal's file system.",
+        'fields' => array(
+          'filename' => array(
+            'description' => 'The path of the primary file for this item, relative to the Drupal root; e.g. modules/node/node.module.',
+            'type' => 'varchar',
+            'length' => 255,
+            'not null' => TRUE,
+            'default' => ''),
+          'name' => array(
+            'description' => 'The name of the item; e.g. node.',
+            'type' => 'varchar',
+            'length' => 255,
+            'not null' => TRUE,
+            'default' => ''),
+          'type' => array(
+            'description' => 'The type of the item, either module, theme, or theme_engine.',
+            'type' => 'varchar',
+            'length' => 255,
+            'not null' => TRUE,
+            'default' => ''),
+          'owner' => array(
+            'description' => "A theme's 'parent'. Can be either a theme or an engine.",
+            'type' => 'varchar',
+            'length' => 255,
+            'not null' => TRUE,
+            'default' => ''),
+          'status' => array(
+            'description' => 'Boolean indicating whether or not this item is enabled.',
+            'type' => 'int',
+            'not null' => TRUE,
+            'default' => 0),
+          'throttle' => array(
+            'description' => 'Boolean indicating whether this item is disabled when the throttle.module disables throttleable items.',
+            'type' => 'int',
+            'not null' => TRUE,
+            'default' => 0,
+            'size' => 'tiny'),
+          'bootstrap' => array(
+            'description' => "Boolean indicating whether this module is loaded during Drupal's early bootstrapping phase (e.g. even before the page cache is consulted).",
+            'type' => 'int',
+            'not null' => TRUE,
+            'default' => 0),
+          'schema_version' => array(
+            'description' => "The module's database schema version number. -1 if the module is not installed (its tables do not exist); 0 or the largest N of the module's hook_update_N() function that has either been run
+   or existed when the module was first installed.",
+            'type' => 'int',
+            'not null' => TRUE,
+            'default' => -1,
+            'size' => 'small'),
+          'weight' => array(
+            'description' => "The order in which this module's hooks should be invoked relative to other modules. Equal-weighted modules are ordered by name.",
+            'type' => 'int',
+            'not null' => TRUE,
+            'default' => 0),
+          'info' => array(
+            'description' => "A serialized array containing information from the module's .info file; keys can include name, description, package, version, core, dependencies, dependents, and php.",
+            'type' => 'text',
+            'not null' => FALSE,
+          )),
+        'primary key' => array('filename'),
+        'indexes' => array(
+          'modules' => array(array('type', 12), 'status', 'weight', 'filename'),
+          'bootstrap' => array(array('type', 12), 'status', 'bootstrap', 'weight', 'filename'),
+          'type_name' => array(array('type', 12), 'name'),
+        ),
+      ),
+    );
+  }
+
+  /**
+   * Sets a module version and status.
+   *
+   * @param $module
+   * @param $version
+   * @param int $status
+   */
+  public function setModuleVersion($module, $version, $status = 1) {
+    $this->createTable('system');
+    $this->database->merge('system')
+      ->key(array('filename' => "modules/$module"))
+      ->fields(array(
+        'type' => 'module',
+        'name' => $module,
+        'schema_version' => $version,
+        'status' => $status,
+      ))
+      ->execute();
+  }
+}
diff --git a/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/d6/MigrateSystemConfigsTest.php b/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/d6/MigrateSystemConfigsTest.php
deleted file mode 100644
index 0764d72..0000000
--- a/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/d6/MigrateSystemConfigsTest.php
+++ /dev/null
@@ -1,192 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\migrate_drupal\Tests\d6\MigrateSystemSiteTest.
- */
-
-namespace Drupal\migrate_drupal\Tests\d6;
-
-use Drupal\migrate\MigrateMessage;
-use Drupal\migrate\MigrateExecutable;
-use Drupal\migrate_drupal\Tests\MigrateDrupalTestBase;
-
-class MigrateSystemConfigsTest extends MigrateDrupalTestBase {
-
-  /**
-   * {@inheritdoc}
-   */
-  public static function getInfo() {
-    return array(
-      'name'  => 'Migrate variables to system.*.yml',
-      'description'  => 'Upgrade variables to system.*.yml',
-      'group' => 'Migrate Drupal',
-    );
-  }
-
-  /**
-   * Tests migration of system (cron) variables to system.cron.yml.
-   */
-  public function testSystemCron() {
-    $migration = entity_load('migration', 'd6_system_cron');
-    $dumps = array(
-      drupal_get_path('module', 'migrate_drupal') . '/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6SystemCron.php',
-    );
-    $this->prepare($migration, $dumps);
-    $executable = new MigrateExecutable($migration, new MigrateMessage());
-    $executable->import();
-    $config = \Drupal::config('system.cron');
-    $this->assertIdentical($config->get('threshold.warning'), 172800);
-    $this->assertIdentical($config->get('threshold.error'), 1209600);
-  }
-
-  /**
-   * Tests migration of system (rss) variables to system.rss.yml.
-   */
-  public function testSystemRss() {
-    $migration = entity_load('migration', 'd6_system_rss');
-    $dumps = array(
-      drupal_get_path('module', 'migrate_drupal') . '/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6SystemRss.php',
-    );
-    $this->prepare($migration, $dumps);
-    $executable = new MigrateExecutable($migration, new MigrateMessage());
-    $executable->import();
-    $config = \Drupal::config('system.rss');
-    $this->assertIdentical($config->get('items.limit'), 10);
-  }
-
-  /**
-   * Tests migration of system (Performance) variables to system.performance.yml.
-   */
-  public function testSystemPerformance() {
-    $migration = entity_load('migration', 'd6_system_performance');
-    $dumps = array(
-      drupal_get_path('module', 'migrate_drupal') . '/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6SystemPerformance.php',
-    );
-    $this->prepare($migration, $dumps);
-    $executable = new MigrateExecutable($migration, new MigrateMessage());
-    $executable->import();
-    $config = \Drupal::config('system.performance');
-    $this->assertIdentical($config->get('css.preprocess'), false);
-    $this->assertIdentical($config->get('js.preprocess'), false);
-    $this->assertIdentical($config->get('cache.page.max_age'), 0);
-  }
-
-  /**
-   * Tests migration of system (theme) variables to system.theme.yml.
-   */
-  public function testSystemTheme() {
-    $migration = entity_load('migration', 'd6_system_theme');
-    $dumps = array(
-      drupal_get_path('module', 'migrate_drupal') . '/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6SystemTheme.php',
-    );
-    $this->prepare($migration, $dumps);
-    $executable = new MigrateExecutable($migration, new MigrateMessage());
-    $executable->import();
-    $config = \Drupal::config('system.theme');
-    $this->assertIdentical($config->get('admin'), '0');
-    $this->assertIdentical($config->get('default'), 'garland');
-  }
-
-  /**
-   * Tests migration of system (maintenance) variables to system.maintenance.yml.
-   */
-  public function testSystemMaintenance() {
-    $migration = entity_load('migration', 'd6_system_maintenance');
-    $dumps = array(
-      drupal_get_path('module', 'migrate_drupal') . '/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6SystemMaintenance.php',
-    );
-    $this->prepare($migration, $dumps);
-    $executable = new MigrateExecutable($migration, new MigrateMessage());
-    $executable->import();
-    $config = \Drupal::config('system.maintenance');
-    $this->assertIdentical($config->get('enable'), 0);
-    $this->assertIdentical($config->get('message'), 'Drupal is currently under maintenance. We should be back shortly. Thank you for your patience.');
-  }
-
-  /**
-   * Tests migration of system (site) variables to system.site.yml.
-   */
-  public function testSystemSite() {
-    $migration = entity_load('migration', 'd6_system_site');
-    $dumps = array(
-      drupal_get_path('module', 'migrate_drupal') . '/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6SystemSite.php',
-    );
-    $this->prepare($migration, $dumps);
-    $executable = new MigrateExecutable($migration, new MigrateMessage());
-    $executable->import();
-    $config = \Drupal::config('system.site');
-    $this->assertIdentical($config->get('name'), 'site_name');
-    $this->assertIdentical($config->get('mail'), 'site_mail@example.com');
-    $this->assertIdentical($config->get('slogan'), 'Migrate rocks');
-    $this->assertIdentical($config->get('page.403'), 'user');
-    $this->assertIdentical($config->get('page.404'), 'page-not-found');
-    $this->assertIdentical($config->get('page.front'), 'node');
-    $this->assertIdentical($config->get('admin_compact_mode'), FALSE);
-  }
-
-  /**
-   * Tests migration of system (filter) variables to system.filter.yml.
-   */
-  public function testSystemFilter() {
-    $migration = entity_load('migration', 'd6_system_filter');
-    $dumps = array(
-      drupal_get_path('module', 'migrate_drupal') . '/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6SystemFilter.php',
-    );
-    $this->prepare($migration, $dumps);
-    $executable = new MigrateExecutable($migration, new MigrateMessage());
-    $executable->import();
-    $config = \Drupal::config('system.filter');
-    $this->assertIdentical($config->get('protocols'), array('http', 'https', 'ftp', 'news', 'nntp', 'tel', 'telnet', 'mailto', 'irc', 'ssh', 'sftp', 'webcal', 'rtsp'));
-  }
-
-  /**
-   * Tests migration of system (image) variables to system.image.yml.
-   */
-  public function testSystemImage() {
-    $migration = entity_load('migration', 'd6_system_image');
-    $dumps = array(
-      drupal_get_path('module', 'migrate_drupal') . '/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6SystemImage.php',
-    );
-    $this->prepare($migration, $dumps);
-    $executable = new MigrateExecutable($migration, new MigrateMessage());
-    $executable->import();
-    $config = \Drupal::config('system.image');
-    $this->assertIdentical($config->get('toolkit'), 'gd');
-  }
-
-  /**
-   * Tests migration of system (image GD) variables to system.image.gd.yml.
-   */
-  public function testSystemImageGd() {
-    $migration = entity_load('migration', 'd6_system_image_gd');
-    $dumps = array(
-      drupal_get_path('module', 'migrate_drupal') . '/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6SystemImageGd.php',
-    );
-    $this->prepare($migration, $dumps);
-    $executable = new MigrateExecutable($migration, new MigrateMessage());
-    $executable->import();
-    $config = \Drupal::config('system.image.gd');
-    $this->assertIdentical($config->get('jpeg_quality'), 75);
-  }
-
-  /**
-   * Tests migration of system (file) variables to system.file.yml.
-   */
-  public function testSystemFile() {
-    $migration = entity_load('migration', 'd6_system_file');
-    $dumps = array(
-      drupal_get_path('module', 'migrate_drupal') . '/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6SystemFile.php',
-    );
-    $this->prepare($migration, $dumps);
-    $executable = new MigrateExecutable($migration, new MigrateMessage());
-    $executable->import();
-    $old_state = \Drupal::configFactory()->getOverrideState();
-    \Drupal::configFactory()->setOverrideState(FALSE);
-    $config = \Drupal::config('system.file');
-    $this->assertIdentical($config->get('path.private'), 'files/test');
-    $this->assertIdentical($config->get('path.temporary'), 'files/temp');
-    \Drupal::configFactory()->setOverrideState($old_state);
-  }
-
-}
diff --git a/core/modules/migrate_drupal/migrate_drupal.services.yml b/core/modules/migrate_drupal/migrate_drupal.services.yml
new file mode 100644
index 0000000..8ed0b5c
--- /dev/null
+++ b/core/modules/migrate_drupal/migrate_drupal.services.yml
@@ -0,0 +1,4 @@
+services:
+  plugin.manager.migrate.load:
+    class: Drupal\migrate\Plugin\MigratePluginManager
+    arguments: [load, '@container.namespaces', '@cache.cache', '@language_manager', '@module_handler']
\ No newline at end of file
diff --git a/core/modules/migrate_drupal/tests/Drupal/migrate_drupal/Tests/D6VariableTest.php b/core/modules/migrate_drupal/tests/Drupal/migrate_drupal/Tests/D6VariableTest.php
deleted file mode 100644
index 7853b12..0000000
--- a/core/modules/migrate_drupal/tests/Drupal/migrate_drupal/Tests/D6VariableTest.php
+++ /dev/null
@@ -1,77 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\migrate\Tests\D6VariableSourceTest.
- */
-
-namespace Drupal\migrate_drupal\Tests;
-
-use Drupal\migrate\Tests\MigrateSqlSourceTestCase;
-
-/**
- * @group migrate_drupal
- * @group Drupal
- */
-class D6VariableTest extends MigrateSqlSourceTestCase {
-
-  const PLUGIN_CLASS = 'Drupal\migrate_drupal\Plugin\migrate\source\d6\Variable';
-
-  protected $migrationConfiguration = array(
-    'id' => 'test',
-    'highwaterProperty' => array('field' => 'test'),
-    'idlist' => array(),
-    'source' => array(
-      'plugin' => 'drupal6_variable',
-      'variables' => array(
-        'foo',
-        'bar',
-      ),
-    ),
-    'sourceIds' => array(),
-    'destinationIds' => array(),
-  );
-
-  protected $mapJoinable = FALSE;
-
-  protected $expectedResults = array(
-    array(
-      'foo' => 1,
-      'bar' => FALSE,
-    ),
-  );
-
-  protected $databaseContents = array(
-    'variable' => array(
-      array('name' => 'foo', 'value' => 'i:1;'),
-      array('name' => 'bar', 'value' => 'b:0;'),
-    ),
-  );
-
-  /**
-   * {@inheritdoc}
-   */
-  public static function getInfo() {
-    return array(
-      'name' => 'D6 variable source functionality',
-      'description' => 'Tests D6 variable source plugin.',
-      'group' => 'Migrate Drupal',
-    );
-  }
-
-}
-
-namespace Drupal\migrate_drupal\Tests\source\d6;
-
-use Drupal\Core\Database\Connection;
-use Drupal\Core\Extension\ModuleHandlerInterface;
-use Drupal\migrate_drupal\Plugin\migrate\source\d6\Variable;
-
-class TestVariable extends Variable {
-  function setDatabase(Connection $database) {
-    $this->database = $database;
-  }
-  function setModuleHandler(ModuleHandlerInterface $module_handler) {
-    $this->moduleHandler = $module_handler;
-  }
-}
diff --git a/core/modules/migrate_drupal/tests/Drupal/migrate_drupal/Tests/source/VariableTest.php b/core/modules/migrate_drupal/tests/Drupal/migrate_drupal/Tests/source/VariableTest.php
new file mode 100644
index 0000000..e23f02c
--- /dev/null
+++ b/core/modules/migrate_drupal/tests/Drupal/migrate_drupal/Tests/source/VariableTest.php
@@ -0,0 +1,72 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\migrate\Tests\source\VariableTest.
+ */
+
+namespace Drupal\migrate_drupal\Tests\source\d6;
+
+use Drupal\migrate\Tests\MigrateSqlSourceTestCase;
+
+/**
+ * @group migrate_drupal
+ * @group Drupal
+ */
+class VariableTest extends MigrateSqlSourceTestCase {
+
+  const PLUGIN_CLASS = 'Drupal\migrate_drupal\Plugin\migrate\source\Variable';
+
+  protected $migrationConfiguration = array(
+    'id' => 'test',
+    'highwaterProperty' => array('field' => 'test'),
+    'idlist' => array(),
+    'source' => array(
+      'plugin' => 'd6_variable',
+      'variables' => array(
+        'foo',
+        'bar',
+      ),
+    ),
+  );
+
+  protected $expectedResults = array(
+    array(
+      'foo' => 1,
+      'bar' => FALSE,
+    ),
+  );
+
+  protected $databaseContents = array(
+    'variable' => array(
+      array('name' => 'foo', 'value' => 'i:1;'),
+      array('name' => 'bar', 'value' => 'b:0;'),
+    ),
+  );
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function getInfo() {
+    return array(
+      'name' => 'D6 variable source functionality',
+      'description' => 'Tests D6 variable source plugin.',
+      'group' => 'Migrate Drupal',
+    );
+  }
+
+}
+
+namespace Drupal\migrate_drupal\Tests\source;
+
+use Drupal\Core\Database\Connection;
+use Drupal\Core\Extension\ModuleHandlerInterface;
+
+class TestVariable extends \Drupal\migrate_drupal\Plugin\migrate\source\Variable {
+  public function setDatabase(Connection $database) {
+    $this->database = $database;
+  }
+  public function setModuleHandler(ModuleHandlerInterface $module_handler) {
+    $this->moduleHandler = $module_handler;
+  }
+}
