diff --git a/core/includes/config.inc b/core/includes/config.inc
index 0b83f60..42ed211 100644
--- a/core/includes/config.inc
+++ b/core/includes/config.inc
@@ -2,7 +2,6 @@
 
 use Drupal\Core\Config\Config;
 use Drupal\Core\Config\FileStorage;
-use Drupal\Core\Config\NullStorage;
 use Drupal\Core\Config\StorageInterface;
 
 /**
@@ -24,28 +23,23 @@
  *   The name of the module or theme to install default configuration for.
  */
 function config_install_default_config($type, $name) {
-  // If this module defines any ConfigEntity types then create an empty
-  // manifest file for each of them.
-  foreach (config_get_module_config_entities($name) as $entity_info) {
+  // If this module defines any ConfigEntity types, then create a manifest file
+  // for each of them with a listing of the objects it maintains.
+  foreach (config_get_module_config_entities($name) as $entity_type => $entity_info) {
     config('manifest.' . $entity_info['config_prefix'])->save();
   }
 
   $config_dir = drupal_get_path($type, $name) . '/config';
   if (is_dir($config_dir)) {
     $source_storage = new FileStorage($config_dir);
-    $target_storage = drupal_container()->get('config.storage');
-
-    // Ignore manifest files.
-    $config_changes = config_sync_get_changes($source_storage, $target_storage, FALSE);
-    if (empty($config_changes['create'])) {
-      return;
-    }
-
-    // Do not overwrite or delete pre-existing configuration.
-    $config_changes['change'] = array();
-    $config_changes['delete'] = array();
-    $remaining_changes = config_import_invoke_owner($config_changes, $source_storage, $target_storage);
-    config_sync_changes($remaining_changes, $source_storage, $target_storage);
+    drupal_container()->get('config.installer')->setSourceStorage($source_storage)
+      // Ignore manifest files when creating changelist to import.
+      ->defaultChangelist(FALSE)
+      // Only import new config. Changed config is from previous enables and
+      // should not be overwritten.
+      ->removeChangelist('delete')
+      ->removeChangelist('change')
+      ->import();
   }
 }
 
@@ -100,108 +94,6 @@ function config($name) {
 }
 
 /**
- * Returns a list of differences between configuration storages.
- *
- * @param Drupal\Core\Config\StorageInterface $source_storage
- *   The storage to synchronize configuration from.
- * @param Drupal\Core\Config\StorageInterface $target_storage
- *   The storage to synchronize configuration to.
- * @param bool $use_manifest
- *   (optional) Whether to determine changes based on manifest files. Defaults
- *   to TRUE.
- *
- * @return array|bool
- *   An associative array containing the differences between source and target
- *   storage, or FALSE if there are no differences.
- */
-function config_sync_get_changes(StorageInterface $source_storage, StorageInterface $target_storage, $use_manifest = TRUE) {
-  $config_changes = array(
-    'create' => array(),
-    'change' => array(),
-    'delete' => array(),
-  );
-  $all_source_names = $source_storage->listAll();
-  $all_target_names = $target_storage->listAll();
-
-  // Config entities maintain 'manifest' files that list the objects they
-  // are currently handling. Each file is a simple indexed array of config
-  // object names. In order to generate a list of objects that have been
-  // created or deleted we need to open these files in both the source and
-  // target storage, generate an array of the objects, and compare them.
-  if ($use_manifest) {
-    $source_config_data = array();
-    $target_config_data = array();
-    foreach ($source_storage->listAll('manifest') as $name) {
-      if ($source_manifest_data = $source_storage->read($name)) {
-        $source_config_data = array_merge($source_config_data, $source_manifest_data);
-      }
-
-      if ($target_manifest_data = $target_storage->read($name)) {
-        $target_config_data = array_merge($target_config_data, $target_manifest_data);
-      }
-    }
-
-    foreach (array_diff_key($target_config_data, $source_config_data) as $name => $value) {
-      $config_changes['delete'][] = $value['name'];
-    }
-
-    foreach (array_diff_key($source_config_data, $target_config_data) as $name => $value) {
-      $config_changes['create'][] = $value['name'];
-    }
-  }
-  else {
-    $config_changes['delete'] = array_diff($all_target_names, $all_source_names);
-    $config_changes['create'] = array_diff($all_source_names, $all_target_names);
-  }
-
-  foreach (array_intersect($all_source_names, $all_target_names) as $name) {
-    // Ignore manifest files
-    if (substr($name, 0, 9) != 'manifest.') {
-      $source_config_data = $source_storage->read($name);
-      $target_config_data = $target_storage->read($name);
-      if ($source_config_data !== $target_config_data) {
-        $config_changes['change'][] = $name;
-      }
-    }
-  }
-
-  // Do not trigger subsequent synchronization operations if there are no
-  // changes in any category.
-  if (empty($config_changes['create']) && empty($config_changes['change']) && empty($config_changes['delete'])) {
-    return FALSE;
-  }
-  return $config_changes;
-}
-
-/**
- * Writes an array of config file changes from a source storage to a target storage.
- *
- * @param array $config_changes
- *   An array of changes to be written.
- * @param Drupal\Core\Config\StorageInterface $source_storage
- *   The storage to synchronize configuration from.
- * @param Drupal\Core\Config\StorageInterface $target_storage
- *   The storage to synchronize configuration to.
- */
-function config_sync_changes(array $config_changes, StorageInterface $source_storage, StorageInterface $target_storage) {
-  $factory = drupal_container()->get('config.factory');
-  foreach (array('delete', 'create', 'change') as $op) {
-    foreach ($config_changes[$op] as $name) {
-      $config = new Config($name, $target_storage);
-      if ($op == 'delete') {
-        $config->delete();
-      }
-      else {
-        $data = $source_storage->read($name);
-        $config->setData($data ? $data : array());
-        $config->save();
-      }
-      $factory->reset($name);
-    }
-  }
-}
-
-/**
  * Imports configuration into the active configuration.
  *
  * @return bool|null
@@ -209,13 +101,10 @@ function config_sync_changes(array $config_changes, StorageInterface $source_sto
  *   synchronization error, or NULL if there are no changes to synchronize.
  */
 function config_import() {
-  // Retrieve a list of differences between staging and the active configuration.
-  $source_storage = drupal_container()->get('config.storage.staging');
-  $snapshot_storage = drupal_container()->get('config.storage.snapshot');
-  $target_storage = drupal_container()->get('config.storage');
+  $config_importer = drupal_container()->get('config.importer');
 
-  $config_changes = config_sync_get_changes($source_storage, $target_storage);
-  if (empty($config_changes)) {
+  // Retrieve a list of differences between staging and the active configuration.
+  if (!$config_importer->hasChanges()) {
     return;
   }
 
@@ -230,9 +119,7 @@ function config_import() {
 
   $success = TRUE;
   try {
-    $remaining_changes = config_import_invoke_owner($config_changes, $source_storage, $target_storage);
-    config_sync_changes($remaining_changes, $source_storage, $target_storage);
-    config_import_create_snapshot($target_storage, $snapshot_storage);
+    $config_importer->import();
   }
   catch (ConfigException $e) {
     watchdog_exception('config_import', $e);
@@ -244,67 +131,6 @@ function config_import() {
 }
 
 /**
- * Creates a configuration snapshot following a successful import.
- *
- * @param Drupal\Core\Config\StorageInterface $source_storage
- *   The storage to synchronize configuration from.
- * @param Drupal\Core\Config\StorageInterface $target_storage
- *   The storage to synchronize configuration to.
- */
-function config_import_create_snapshot(StorageInterface $source_storage, StorageInterface $snapshot_storage) {
-  $snapshot_storage->deleteAll();
-  foreach ($source_storage->listAll() as $name) {
-    $snapshot_storage->write($name, $source_storage->read($name));
-  }
-}
-
-/**
- * Invokes MODULE_config_import() callbacks for configuration changes.
- *
- * @param array $config_changes
- *   An array of changes to be loaded.
- * @param Drupal\Core\Config\StorageInterface $source_storage
- *   The storage to synchronize configuration from.
- * @param Drupal\Core\Config\StorageInterface $target_storage
- *   The storage to synchronize configuration to.
- *
- * @todo Add support for other extension types; e.g., themes etc.
- */
-function config_import_invoke_owner(array $config_changes, StorageInterface $source_storage, StorageInterface $target_storage) {
-  // Allow modules to take over configuration change operations for
-  // higher-level configuration data.
-  // First pass deleted, then new, and lastly changed configuration, in order to
-  // handle dependencies correctly.
-  $manager = drupal_container()->get('plugin.manager.entity');
-  foreach (array('delete', 'create', 'change') as $op) {
-    foreach ($config_changes[$op] as $key => $name) {
-      // Call to the configuration entity's storage controller to handle the
-      // configuration change.
-      $handled_by_module = FALSE;
-      // Validate the configuration object name before importing it.
-      Config::validateName($name);
-      if ($entity_type = config_get_entity_type_by_name($name)) {
-        $old_config = new Config($name, $target_storage);
-        $old_config->load();
-
-        $data = $source_storage->read($name);
-        $new_config = new Config($name, $target_storage);
-        if ($data !== FALSE) {
-          $new_config->setData($data);
-        }
-
-        $method = 'import' . ucfirst($op);
-        $handled_by_module = $manager->getStorageController($entity_type)->$method($name, $new_config, $old_config);
-      }
-      if (!empty($handled_by_module)) {
-        unset($config_changes[$op][$key]);
-      }
-    }
-  }
-  return $config_changes;
-}
-
-/**
  * Return a list of all config entity types provided by a module.
  *
  * @param string $module
@@ -352,3 +178,18 @@ function config_get_entity_type_by_name($name) {
 function config_typed() {
   return drupal_container()->get('config.typed');
 }
+
+/**
+ * Creates a configuration snapshot following a successful import.
+ *
+ * @param Drupal\Core\Config\StorageInterface $source_storage
+ *   The storage to synchronize configuration from.
+ * @param Drupal\Core\Config\StorageInterface $target_storage
+ *   The storage to synchronize configuration to.
+ */
+function config_import_create_snapshot(StorageInterface $source_storage, StorageInterface $snapshot_storage) {
+  $snapshot_storage->deleteAll();
+  foreach ($source_storage->listAll() as $name) {
+    $snapshot_storage->write($name, $source_storage->read($name));
+  }
+}
diff --git a/core/lib/Drupal/Core/Config/ConfigImporter.php b/core/lib/Drupal/Core/Config/ConfigImporter.php
new file mode 100644
index 0000000..be43654
--- /dev/null
+++ b/core/lib/Drupal/Core/Config/ConfigImporter.php
@@ -0,0 +1,414 @@
+<?php
+/**
+ * @file
+ * Contains \Drupal\Core\Config\ConfigImporter.
+ */
+
+namespace Drupal\Core\Config;
+
+use Symfony\Component\EventDispatcher\EventDispatcher;
+
+class ConfigImporter {
+
+  /*
+   * The name of the ConfigImporter. Used to identify events.
+   *
+   * @var string
+   */
+  protected $serviceName;
+
+  /**
+   * The source storage used to discover configuration changes.
+   *
+   * @var \Drupal\Core\Config\StorageInterface
+   */
+  protected $sourceStorage;
+
+  /**
+   * The target storage used to write configuration changes.
+   *
+   * @var \Drupal\Core\Config\StorageInterface
+   */
+  protected $targetStorage;
+
+  /**
+   * The event dispatcher used to notify subscribers.
+   *
+   * @var \Symfony\Component\EventDispatcher\EventDispatcher
+   */
+  protected $eventDispatcher;
+
+  /**
+   * List of changes to import from the source storage to the target
+   * storage.
+   *
+   * @var array
+   */
+  protected $changelist;
+
+  /**
+   * List of changes processed by the import().
+   *
+   * @var array
+   */
+  protected $processed;
+
+  /*
+   * Indicates is the list of changelist has been validated.
+   *
+   * @var bool
+   */
+  protected $validated;
+
+  /**
+   * Constructs a configuration import object.
+   *
+   * @param string $service_name
+   *   The name of the config importer service. Used by notify to dispatch
+   *   service specific events.
+   * @param \Drupal\Core\Config\StorageInterface $targetStorage
+   *   A storage controller object to use for writing the configuration changes
+   *   to.
+   * @param \Symfony\Component\EventDispatcher\EventDispatcher $event_dispatcher
+   *   The event dispatcher used to notify subscribers.
+   */
+  public function __construct($service_name, StorageInterface $target_storage, EventDispatcher $event_dispatcher) {
+    $this->serviceName = $service_name;
+    $this->targetStorage = $target_storage;
+    $this->eventDispatcher = $event_dispatcher;
+  }
+
+  /*
+   * Sets the configuration source storage.
+   *
+   * @param \Drupal\Core\Config\StorageInterface $sourceStorage
+   *   Storage controller object used to read configuration changes from.
+   *
+   * @return \Drupal\Core\Config\ConfigImporter
+   *   The ConfigImporter instance.
+   */
+  public function setSourceStorage(StorageInterface $sourceStorage) {
+    $this->sourceStorage = $sourceStorage;
+    $this->resetLists();
+    return $this;
+  }
+
+  /*
+   * Gets the configuration source storage.
+   *
+   * @return \Drupal\Core\Config\StorageInterface
+   *   Storage controller object used to read configuration changes from.
+   */
+  public function getSourceStorage() {
+    // @todo throw error if not set.
+    return $this->sourceStorage;
+  }
+  /**
+   * Gets an empty changelist.
+   *
+   * @return array
+   *   An empty changelist array.
+   */
+  protected function getEmptyChangelist() {
+    return array(
+      'create' => array(),
+      'change' => array(),
+      'delete' => array(),
+    );
+  }
+
+  /**
+   * Gets the list of differences to import.
+   *
+   * @return array
+   *   An array of config changes that are yet to be imported.
+   */
+  public function getChangelist() {
+    return $this->changelist;
+  }
+
+  /**
+   * Sets the list of differences to import.
+   *
+   * @param array $changelist
+   *   An array of change operations to perform.
+   *
+   * @return \Drupal\Core\Config\ConfigImporter
+   *   The ConfigImporter instance.
+   */
+  public function setChangelist(array $changelist) {
+    $this->changelist = $changelist;
+    $this->validated = FALSE;
+    return $this;
+  }
+
+  /*
+   * Add changes to the changelist.
+   *
+   * @param string $op
+   *   The change operation performed. Either create, change or delete.
+   * @param array $changes
+   *   Array of changes to add the changelist.
+   *
+   * @return \Drupal\Core\Config\ConfigImporter
+   *   The ConfigImporter instance.
+   */
+  public function addChangeList($op, array $changes) {
+    // Only add changes that aren't already listed.
+    $changes = array_diff($changes, $this->changelist[$op]);
+    $this->changelist[$op] = array_merge($this->changelist[$op], $changes);
+    $this->validated = FALSE;
+    return $this;
+  }
+
+  /*
+   * Removes changes from the changelist.
+   *
+   * @param string $op
+   *   The change operation to be reset.
+   *
+   * @return \Drupal\Core\Config\ConfigImporter
+   *   The ConfigImporter instance.
+   */
+  public function removeChangeList($op) {
+    $this->changelist[$op] = array();
+    return $this;
+  }
+
+  /*
+   * Resets the changelist and processed list.
+   *
+   * @return \Drupal\Core\Config\ConfigImporter
+   *  The ConfigImporter instance.
+   */
+  public function resetLists() {
+    $this->processed = $this->changelist = $this->getEmptyChangelist();
+    $this->validated = FALSE;
+    return $this;
+  }
+
+  /**
+   * Add differences between source and target configuration storage to changelist.
+   *
+   * @param bool $use_manifest
+   *   Use manifest to compare storages. Defaults to TRUE.
+   *
+   * @return \Drupal\Core\Config\ConfigImporter
+   *   The ConfigImporter instance.
+   */
+  public function defaultChangelist($use_manifest = TRUE) {
+
+    // Only calculate the changelist if there are no changes in the list.
+    if (!$this->hasChanges()) {
+      $all_source_names = $this->getSourceStorage()->listAll();
+      $all_target_names = $this->targetStorage->listAll();
+
+      // Config entities maintain 'manifest' files that list the objects they
+      // are currently handling. Each file is a simple indexed array of config
+      // object names. In order to generate a list of objects that have been
+      // created or deleted we need to open these files in both the source and
+      // target storage, generate an array of the objects, and compare them.
+      if ($use_manifest) {
+        $source_config_data = array();
+        $target_config_data = array();
+        foreach ($this->getSourceStorage()->listAll('manifest') as $name) {
+          if ($source_manifest_data = $this->getSourceStorage()->read($name)) {
+            $source_config_data = array_merge($source_config_data, $source_manifest_data);
+          }
+
+          if ($target_manifest_data = $this->targetStorage->read($name)) {
+            $target_config_data = array_merge($target_config_data, $target_manifest_data);
+          }
+        }
+
+        foreach (array_diff_key($target_config_data, $source_config_data) as $value) {
+          $this->addChangeList('delete', array($value['name']));
+        }
+
+        foreach (array_diff_key($source_config_data, $target_config_data) as $value) {
+          $this->addChangeList('create', array($value['name']));
+        }
+      }
+      else {
+        $this->addChangeList('delete', array_diff($all_target_names, $all_source_names));
+        $this->addChangeList('create', array_diff($all_source_names, $all_target_names));
+      }
+
+      foreach (array_intersect($all_source_names, $all_target_names) as $name) {
+        // Ignore manifest files
+        if (substr($name, 0, 9) != 'manifest.') {
+          $source_config_data = $this->getSourceStorage()->read($name);
+          $target_config_data = $this->targetStorage->read($name);
+          if ($source_config_data !== $target_config_data) {
+            $this->addChangeList('change', array($name));
+          }
+        }
+      }
+    }
+    return $this;
+  }
+
+  /**
+   * Checks if there is a changelist with changes to process.
+   *
+   * @return bool
+   *   TRUE if there are changes to process and FALSE if not.
+   */
+  public function hasChanges() {
+    foreach (array('delete', 'create', 'change') as $op) {
+      if (count($this->getUnprocessed($op))) {
+        return TRUE;
+      }
+    }
+    return FALSE;
+  }
+
+  /**
+   * Gets list of processed changes.
+   *
+   * @return array
+   *   An array containing a list of processed changes.
+   */
+  public function getProcessed() {
+    return $this->processed;
+  }
+
+  /**
+   * Sets a change as processed.
+   *
+   * @param string $op
+   *   The change operation performed. Either create, change or delete.
+   * @param string $name
+   *   The name of the configuration processed.
+   */
+  protected function setProcessed($op, $name) {
+    $this->processed[$op][] = $name;
+  }
+
+  /**
+   * Gets a list of unprocessed changes for a given operation.
+   *
+   * @param $op
+   *   The change operation to get the unprocessed list for. Either create,
+   *   change or delete.
+   *
+   * @return array
+   *   An array of configuration names.
+   */
+  public function getUnprocessed($op) {
+    return array_diff($this->changelist[$op], $this->processed[$op]);
+  }
+
+  /**
+   * Imports the changelist to the target storage.
+   *
+   * @throws \Drupal\Core\Config\ConfigException
+   *
+   * @return \Drupal\Core\Config\ConfigImporter
+   *   The ConfigImporter instance.
+   */
+  public function import() {
+    if ($this->hasChanges()) {
+      // Ensure that the changes have been validated.
+      $this->validate();
+
+      $this->importInvokeOwner();
+      $this->importConfig();
+
+      // Allow modules to react to a import.
+      $this->notify('import');
+
+      // We're done.
+      $this->resetLists();
+    }
+    return $this;
+  }
+
+  /**
+   * Dispatches validate event for a ConfigImporter object.
+   *
+   * Events should throw a \Drupal\Core\Config\ConfigImporterException to
+   * prevent an import from occurring.
+   */
+  public function validate() {
+    if (!$this->validated) {
+      $this->notify('validate');
+      $this->validated = TRUE;
+    }
+    return $this;
+  }
+
+  /**
+   * Writes an array of config changes from the source to the target storage.
+   *
+   * The changelist is modified as each change is processed.
+   */
+  protected function importConfig() {
+    $factory = drupal_container()->get('config.factory');
+    foreach (array('delete', 'create', 'change') as $op) {
+      foreach ($this->getUnprocessed($op) as $name) {
+        $config = new Config($name, $this->targetStorage);
+        if ($op == 'delete') {
+          $config->delete();
+        }
+        else {
+          $data = $this->getSourceStorage()->read($name);
+          $config->setData($data ? $data : array());
+          $config->save();
+        }
+        $factory->reset($name);
+        $this->setProcessed($op, $name);
+      }
+    }
+  }
+
+  /**
+   * Invokes import* methods on configuration entity storage controllers.
+   *
+   * The changelist is modified as each change is processed.
+   *
+   * @todo Add support for other extension types; e.g., themes etc.
+   */
+  protected function importInvokeOwner() {
+    // Allow modules to take over configuration change operations for
+    // higher-level configuration data.
+    // First pass deleted, then new, and lastly changed configuration, in order to
+    // handle dependencies correctly.
+    $manager = drupal_container()->get('plugin.manager.entity');
+    foreach (array('delete', 'create', 'change') as $op) {
+      foreach ($this->getUnprocessed($op) as $name) {
+        // Call to the configuration entity's storage controller to handle the
+        // configuration change.
+        $handled_by_module = FALSE;
+        // Validate the configuration object name before importing it.
+        // Config::validateName($name);
+        if ($entity_type = config_get_entity_type_by_name($name)) {
+          $old_config = new Config($name, $this->targetStorage);
+          $old_config->load();
+
+          $data = $this->getSourceStorage()->read($name);
+          $new_config = new Config($name, $this->targetStorage);
+          if ($data !== FALSE) {
+            $new_config->setData($data);
+          }
+
+          $method = 'import' . ucfirst($op);
+          $handled_by_module = $manager->getStorageController($entity_type)->$method($name, $new_config, $old_config);
+        }
+        if (!empty($handled_by_module)) {
+          $this->setProcessed($op, $name);
+        }
+      }
+    }
+  }
+
+  /**
+   * Dispatches a config importer event.
+   *
+   * @param string $event_name
+   *   The name of the config importer event to dispatch.
+   */
+  protected function notify($event_name) {
+    $this->eventDispatcher->dispatch($this->serviceName . '.' . $event_name, new ConfigImporterEvent($this));
+  }
+}
diff --git a/core/lib/Drupal/Core/Config/ConfigImporterEvent.php b/core/lib/Drupal/Core/Config/ConfigImporterEvent.php
new file mode 100644
index 0000000..37e343f
--- /dev/null
+++ b/core/lib/Drupal/Core/Config/ConfigImporterEvent.php
@@ -0,0 +1,39 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\Config\ConfigImporterEvent.
+ */
+
+namespace Drupal\Core\Config;
+
+use Symfony\Component\EventDispatcher\Event;
+
+class ConfigImporterEvent extends Event {
+  /**
+   * Configuration import object.
+   *
+   * @var \Drupal\Core\Config\ConfigImporter
+   */
+  protected $configImporter;
+
+  /**
+   * Constructs ConfigImporterEvent.
+   *
+   * @param \Drupal\Core\Config\ConfigImporter $config_importer
+   *   A config import object to notify listeners about.
+   */
+  public function __construct(ConfigImporter $config_importer) {
+    $this->configImporter = $config_importer;
+  }
+
+  /**
+   * Gets the config import object.
+   *
+   * @return \Drupal\Core\Config\ConfigImporter
+   *   The ConfigImporter object.
+   */
+  public function getConfigImporter() {
+    return $this->configImporter;
+  }
+}
diff --git a/core/lib/Drupal/Core/Config/ConfigImporterException.php b/core/lib/Drupal/Core/Config/ConfigImporterException.php
new file mode 100644
index 0000000..fd18c4d
--- /dev/null
+++ b/core/lib/Drupal/Core/Config/ConfigImporterException.php
@@ -0,0 +1,13 @@
+<?php
+
+/**
+* @file
+* Contains \Drupal\Core\Config\ConfigImporterException.
+*/
+
+namespace Drupal\Core\Config;
+
+/**
+* Exception thrown when a config import fails.
+*/
+class ConfigImporterException extends ConfigException {}
diff --git a/core/lib/Drupal/Core/CoreBundle.php b/core/lib/Drupal/Core/CoreBundle.php
index cc4e4aa..f040921 100644
--- a/core/lib/Drupal/Core/CoreBundle.php
+++ b/core/lib/Drupal/Core/CoreBundle.php
@@ -77,6 +77,21 @@ public function build(ContainerBuilder $container) {
       ->addArgument(new Reference('config.storage'))
       ->addArgument(new Reference('config.storage.schema'));
 
+    // Register configuration importer and installer.
+    $container
+      ->register('config.importer', 'Drupal\Core\Config\ConfigImporter')
+      ->addArgument('config.importer')
+      ->addArgument(new Reference('config.storage'))
+      ->addArgument(new Reference('event_dispatcher'))
+      ->addMethodCall('setSourceStorage' ,array(new Reference('config.storage.staging')))
+      ->addMethodCall('defaultChangelist', array()) ;
+
+    $container
+      ->register('config.installer', 'Drupal\Core\Config\ConfigImporter')
+      ->addArgument('config.installer')
+      ->addArgument(new Reference('config.storage'))
+      ->addArgument(new Reference('event_dispatcher'));
+
     // Register the service for the default database connection.
     $container->register('database', 'Drupal\Core\Database\Connection')
       ->setFactoryClass('Drupal\Core\Database\Database')
@@ -264,6 +279,10 @@ public function build(ContainerBuilder $container) {
       ->addTag('event_subscriber');
     $container->register('config_global_override_subscriber', 'Drupal\Core\EventSubscriber\ConfigGlobalOverrideSubscriber')
       ->addTag('event_subscriber');
+    $container->register('config_snapshot_subscriber', 'Drupal\Core\EventSubscriber\ConfigSnapshotSubscriber')
+      ->addArgument(new Reference('config.storage'))
+      ->addArgument(new Reference('config.storage.snapshot'))
+      ->addTag('event_subscriber');
     $container->register('language_request_subscriber', 'Drupal\Core\EventSubscriber\LanguageRequestSubscriber')
       ->addArgument(new Reference('language_manager'))
       ->addTag('event_subscriber');
diff --git a/core/lib/Drupal/Core/EventSubscriber/ConfigSnapshotSubscriber.php b/core/lib/Drupal/Core/EventSubscriber/ConfigSnapshotSubscriber.php
new file mode 100644
index 0000000..ca06246
--- /dev/null
+++ b/core/lib/Drupal/Core/EventSubscriber/ConfigSnapshotSubscriber.php
@@ -0,0 +1,59 @@
+<?php
+/**
+ * @file
+ * Definition of Drupal\Core\EventSubscriber\ConfigGlobalOverrideSubscriber.
+ */
+
+namespace Drupal\Core\EventSubscriber;
+
+use Drupal\Core\Config\Config;
+use Drupal\Core\Config\StorageInterface;
+use Drupal\Core\Config\ConfigImporterEvent;
+use Symfony\Component\EventDispatcher\EventSubscriberInterface;
+
+/**
+ * Create a snapshot when config is imported.
+ */
+class ConfigSnapshotSubscriber implements EventSubscriberInterface {
+
+  /**
+   * The source storage used to discover configuration changes.
+   *
+   * @var \Drupal\Core\Config\StorageInterface
+   */
+  protected $sourceStorage;
+
+  /**
+   * The snapshot storage used to write configuration changes.
+   *
+   * @var \Drupal\Core\Config\StorageInterface
+   */
+  protected $snapshotStorage;
+
+  public function __construct(StorageInterface $source_storage, StorageInterface $snapshot_storage) {
+    $this->sourceStorage = $source_storage;
+    $this->snapshotStorage = $snapshot_storage;
+  }
+
+  /**
+   * Create config snapshot.
+   *
+   * @param \Drupal\Core\Config\ConfigImporterEvent $event
+   *   The Event to process.
+   */
+  public function onConfigImporterImport(ConfigImporterEvent $event) {
+    config_import_create_snapshot($this->sourceStorage, $this->snapshotStorage);
+  }
+
+  /**
+   * Registers the methods in this class that should be listeners.
+   *
+   * @return array
+   *   An array of event listener definitions.
+   */
+  static function getSubscribedEvents() {
+    $events['config.importer.import'][] = array('onConfigImporterImport', 40);
+    return $events;
+  }
+
+}
diff --git a/core/modules/config/config.admin.inc b/core/modules/config/config.admin.inc
index 3813885..36df209 100644
--- a/core/modules/config/config.admin.inc
+++ b/core/modules/config/config.admin.inc
@@ -19,7 +19,7 @@
  * @param Drupal\Core\Config\StorageInterface $target_storage
  *   The target storage to compare differences to.
  */
-function config_admin_sync_form(array &$form, array &$form_state, StorageInterface $source_storage, StorageInterface $target_storage) {
+function config_admin_sync_form(array &$form, array &$form_state, StorageInterface $source_storage) {
   $source_list = $source_storage->listAll();
   if (empty($source_list)) {
     $form['no_changes'] = array(
@@ -29,15 +29,16 @@ function config_admin_sync_form(array &$form, array &$form_state, StorageInterfa
     return $form;
   }
 
-  $config_changes = config_sync_get_changes($source_storage, $target_storage);
-  if (empty($config_changes)) {
+
+  $config_import = drupal_container()->get('config.importer');
+  if (!$config_import->hasChanges()) {
     $form['no_changes'] = array(
       '#markup' => t('There are no configuration changes.'),
     );
     return $form;
   }
 
-  foreach ($config_changes as $config_change_type => $config_files) {
+  foreach ($config_import->getChangelist() as $config_change_type => $config_files) {
     if (empty($config_files)) {
       continue;
     }
diff --git a/core/modules/config/lib/Drupal/config/Tests/ConfigCRUDTest.php b/core/modules/config/lib/Drupal/config/Tests/ConfigCRUDTest.php
index e363577..73d2b6d 100644
--- a/core/modules/config/lib/Drupal/config/Tests/ConfigCRUDTest.php
+++ b/core/modules/config/lib/Drupal/config/Tests/ConfigCRUDTest.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\config\Tests;
 
+use Drupal\Core\Config\ConfigImporter;
 use Drupal\Core\Config\ConfigNameException;
 use Drupal\simpletest\DrupalUnitTestBase;
 
@@ -14,6 +15,14 @@
  * Tests CRUD operations on configuration objects.
  */
 class ConfigCRUDTest extends DrupalUnitTestBase {
+
+  /**
+   * Modules to enable.
+   *
+   * @var array
+   */
+  public static $modules = array('system');
+
   public static function getInfo() {
     return array(
       'name' => 'CRUD operations',
@@ -178,11 +187,14 @@ function testNameValidation() {
     $manifest_data['new']['name'] = 'invalid';
     $staging->write('manifest.invalid_object_name', $manifest_data);
 
-    // Verify that an exception is thrown when synchronizing.
+    // Verify that an exception is thrown when importing.
     $message = 'Expected ConfigNameException was thrown when attempting to sync invalid configuration.';
+    $config_importer = new ConfigImporter('config.importer', $storage, $this->container->get('event_dispatcher'));
     try {
-      config_import();
-      $this->fail($message);
+      $config_importer
+        ->setSourceStorage($staging)
+        ->defaultChangelist()
+        ->import();
     }
     catch (ConfigNameException $e) {
       $this->pass($message);
diff --git a/core/modules/config/lib/Drupal/config/Tests/ConfigImportTest.php b/core/modules/config/lib/Drupal/config/Tests/ConfigImporterTest.php
similarity index 87%
rename from core/modules/config/lib/Drupal/config/Tests/ConfigImportTest.php
rename to core/modules/config/lib/Drupal/config/Tests/ConfigImporterTest.php
index 9278269..8ad9750 100644
--- a/core/modules/config/lib/Drupal/config/Tests/ConfigImportTest.php
+++ b/core/modules/config/lib/Drupal/config/Tests/ConfigImporterTest.php
@@ -2,17 +2,25 @@
 
 /**
  * @file
- * Definition of Drupal\config\Tests\ConfigImportTest.
+ * Definition of Drupal\config\Tests\ConfigImporterTest.
  */
 
 namespace Drupal\config\Tests;
 
+use Drupal\Core\Config\ConfigImporter;
 use Drupal\simpletest\DrupalUnitTestBase;
 
 /**
  * Tests importing configuration from files into active configuration.
  */
-class ConfigImportTest extends DrupalUnitTestBase {
+class ConfigImporterTest extends DrupalUnitTestBase {
+
+  /**
+   * Config Importer object used for testing.
+   *
+   * @var \Drupal\Core\Config\ConfigImporter
+   */
+  protected $config_importer;
 
   /**
    * Modules to enable.
@@ -39,6 +47,9 @@ function setUp() {
     // variable being used for recording hook invocations by this test already,
     // so it has to be cleared out manually.
     unset($GLOBALS['hook_config_test']);
+
+    // Set up the ConfigImporter object for testing.
+    $this->config_importer = new ConfigImporter('config.importer', $this->container->get('config.storage'), $this->container->get('event_dispatcher'));
   }
 
   /**
@@ -70,7 +81,10 @@ function testDeleted() {
     // Create an empty manifest to delete the configuration object.
     $staging->write('manifest.config_test.dynamic', array());
     // Import.
-    config_import();
+    $this->config_importer
+      ->setSourceStorage($staging)
+      ->defaultChangelist()
+      ->import();
 
     // Verify the values have disappeared.
     $this->assertIdentical($storage->read($dynamic_name), FALSE);
@@ -87,7 +101,7 @@ function testDeleted() {
     $this->assertTrue(isset($GLOBALS['hook_config_test']['delete']));
 
     // Verify that there is nothing more to import.
-    $this->assertFalse(config_sync_get_changes($staging, $storage));
+    $this->assertFalse($this->config_importer->hasChanges());
   }
 
   /**
@@ -123,7 +137,10 @@ function testNew() {
     $this->assertIdentical($staging->exists($dynamic_name), TRUE, $dynamic_name . ' found.');
 
     // Import.
-    config_import();
+    $this->config_importer
+      ->setSourceStorage($staging)
+      ->defaultChangelist()
+      ->import();
 
     // Verify the values appeared.
     $config = config($dynamic_name);
@@ -138,7 +155,7 @@ function testNew() {
     $this->assertFalse(isset($GLOBALS['hook_config_test']['delete']));
 
     // Verify that there is nothing more to import.
-    $this->assertFalse(config_sync_get_changes($staging, $storage));
+    $this->assertFalse($this->config_importer->hasChanges());
   }
 
   /**
@@ -174,7 +191,10 @@ function testUpdated() {
     $this->assertIdentical($config->get('label'), 'Default');
 
     // Import.
-    config_import();
+    $this->config_importer
+      ->setSourceStorage($staging)
+      ->defaultChangelist()
+      ->import();
 
     // Verify the values were updated.
     $config = config($name);
@@ -195,7 +215,7 @@ function testUpdated() {
     $this->assertFalse(isset($GLOBALS['hook_config_test']['delete']));
 
     // Verify that there is nothing more to import.
-    $this->assertFalse(config_sync_get_changes($staging, $storage));
+    $this->assertFalse($this->config_importer->hasChanges());
   }
 
 }
diff --git a/core/modules/config/lib/Drupal/config/Tests/ConfigSnapshotTest.php b/core/modules/config/lib/Drupal/config/Tests/ConfigSnapshotTest.php
index 439f191..48332d3 100644
--- a/core/modules/config/lib/Drupal/config/Tests/ConfigSnapshotTest.php
+++ b/core/modules/config/lib/Drupal/config/Tests/ConfigSnapshotTest.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\config\Tests;
 
+use Drupal\Core\Config\ConfigImporter;
 use Drupal\simpletest\DrupalUnitTestBase;
 
 /**
@@ -45,21 +46,24 @@ function testSnapshot() {
     $config_key = 'foo';
     $new_data = 'foobar';
 
+    $config_importer = new ConfigImporter('snapshot.comparer', $snapshot, drupal_container()->get('event_dispatcher'));
+    $config_importer->setSourceStorage($active);
+
     // Verify that we have an initial snapshot that matches the active
     // configuration. This has to be true as no config should be installed.
-    $this->assertFalse(config_sync_get_changes($snapshot, $active, FALSE));
+    $this->assertFalse($config_importer->defaultChangelist(FALSE)->hasChanges());
 
     // Install the default config.
     config_install_default_config('module', 'config_test');
     // Although we have imported config this has not affected the snapshot.
-    $this->assertTrue(config_sync_get_changes($snapshot, $active, FALSE));
+    $this->assertTrue($config_importer->resetLists()->defaultChangelist(FALSE)->hasChanges());
 
     // Update the config snapshot.
     config_import_create_snapshot($active, $snapshot);
 
     // The snapshot and active config should now contain the same config
     // objects.
-    $this->assertFalse(config_sync_get_changes($snapshot, $active, FALSE));
+    $this->assertFalse($config_importer->resetLists()->defaultChangelist(FALSE)->hasChanges());
 
     // Change a configuration value in staging.
     $staging_data = config($config_name)->get();
@@ -67,10 +71,9 @@ function testSnapshot() {
     $staging->write($config_name, $staging_data);
 
     // Verify that active and snapshot match, and that staging doesn't match
-    // either of them.
-    $this->assertFalse(config_sync_get_changes($snapshot, $active, FALSE));
-    $this->assertTrue(config_sync_get_changes($snapshot, $staging, FALSE));
-    $this->assertTrue(config_sync_get_changes($staging, $active, FALSE));
+    // active.
+    $this->assertFalse($config_importer->resetLists()->defaultChangelist(FALSE)->hasChanges());
+    $this->assertTrue($config_importer->setSourceStorage($staging)->defaultChangelist(FALSE)->hasChanges());
 
     // Import changed data from staging to active.
     config_import();
@@ -80,7 +83,7 @@ function testSnapshot() {
 
     // Verify that a new snapshot was created which and that it matches
     // the active config.
-    $this->assertFalse(config_sync_get_changes($snapshot, $active, FALSE));
+    $this->assertFalse($config_importer->setSourceStorage($active)->defaultChangelist(FALSE)->hasChanges());
   }
 
 }
diff --git a/core/modules/system/lib/Drupal/system/EventSubscriber/SystemSubscriber.php b/core/modules/system/lib/Drupal/system/EventSubscriber/SystemSubscriber.php
new file mode 100644
index 0000000..74dd7a9
--- /dev/null
+++ b/core/modules/system/lib/Drupal/system/EventSubscriber/SystemSubscriber.php
@@ -0,0 +1,46 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\System\EventSubscriber\SystemSubscriber.
+ */
+
+namespace Drupal\system\EventSubscriber;
+
+use Drupal\Core\Config\Config;
+use Drupal\Core\Config\ConfigImporterEvent;
+use Symfony\Component\EventDispatcher\EventSubscriberInterface;
+
+
+/**
+ * System subscriber for config sync events.
+ */
+class SystemSubscriber implements EventSubscriberInterface {
+
+  /**
+   * Validate the configuration to be imported.
+   *
+   * @param \Drupal\Core\Config\ConfigImporterEvent $event
+   *   The Event to process.
+   */
+  public function onConfigImporterValidate(ConfigImporterEvent $event) {
+    foreach (array('delete', 'create', 'change') as $op) {
+      foreach ($event->getConfigImporter()->getUnprocessed($op) as $name) {
+        Config::validateName($name);
+      }
+    }
+  }
+
+  /**
+   * Registers the methods in this class that should be listeners.
+   *
+   * @return array
+   *   An array of event listener definitions.
+   */
+  static function getSubscribedEvents() {
+    $events['config.importer.validate'][] = array('onConfigImporterValidate', 40);
+    $events['config.installer.validate'][] = array('onConfigImporterValidate', 40);
+    return $events;
+  }
+
+}
diff --git a/core/modules/system/lib/Drupal/system/SystemBundle.php b/core/modules/system/lib/Drupal/system/SystemBundle.php
index 8662169..10147d0 100644
--- a/core/modules/system/lib/Drupal/system/SystemBundle.php
+++ b/core/modules/system/lib/Drupal/system/SystemBundle.php
@@ -25,5 +25,8 @@ public function build(ContainerBuilder $container) {
     // Register the various system plugin manager classes with the dependency
     // injection container.
     $container->register('plugin.manager.system.plugin_ui', 'Drupal\system\Plugin\Type\PluginUIManager');
+
+    $container->register('system.subscriber', 'Drupal\system\EventSubscriber\SystemSubscriber')
+      ->addTag('event_subscriber');
   }
 }
diff --git a/core/modules/system/lib/Drupal/system/Tests/Database/RegressionTest.php b/core/modules/system/lib/Drupal/system/Tests/Database/RegressionTest.php
index 4ad4417..f38b49f 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Database/RegressionTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Database/RegressionTest.php
@@ -12,6 +12,13 @@
  */
 class RegressionTest extends DatabaseTestBase {
 
+  /**
+   * Modules to enable.
+   *
+   * @var array
+   */
+  public static $modules = array('node');
+
   public static function getInfo() {
     return array(
       'name' => 'Regression tests',
diff --git a/core/modules/views/lib/Drupal/views/Tests/ViewTestData.php b/core/modules/views/lib/Drupal/views/Tests/ViewTestData.php
index 232a847..eeef23b 100644
--- a/core/modules/views/lib/Drupal/views/Tests/ViewTestData.php
+++ b/core/modules/views/lib/Drupal/views/Tests/ViewTestData.php
@@ -39,12 +39,6 @@ public static function importTestViews($class, $modules = array()) {
       $class = get_parent_class($class);
     }
     if (!empty($views)) {
-      $target_storage = drupal_container()->get('config.storage');
-      $config_changes = array(
-        'delete' => array(),
-        'create' => array(),
-        'change' => array(),
-      );
       foreach ($modules as $module) {
         $config_dir = drupal_get_path('module', $module) . '/test_views';
         if (!is_dir($config_dir) || !module_exists($module)) {
@@ -52,16 +46,16 @@ public static function importTestViews($class, $modules = array()) {
         }
 
         $source_storage = new FileStorage($config_dir);
+        $config_importer = drupal_container()->get('config.installer')->setSourceStorage($source_storage);
+        // Only import views used by test.
+        $views_to_import = array();
         foreach ($source_storage->listAll('views.view.') as $config_name) {
           $id = str_replace('views.view.', '', $config_name);
           if (in_array($id, $views)) {
-            $config_changes['create'][] = $config_name;
+            $views_to_import[] = $config_name;
           }
         }
-      }
-      if (!empty($config_changes['create'])) {
-        $remaining_changes = config_import_invoke_owner($config_changes, $source_storage, $target_storage);
-        config_sync_changes($remaining_changes, $source_storage, $target_storage);
+        $config_importer->addChangelist('create', $views_to_import)->import();
       }
     }
   }
