diff --git a/core/lib/Drupal/Core/Config/CachedStorage.php b/core/lib/Drupal/Core/Config/CachedStorage.php
index a5d11fd..30ad1f7 100644
--- a/core/lib/Drupal/Core/Config/CachedStorage.php
+++ b/core/lib/Drupal/Core/Config/CachedStorage.php
@@ -8,12 +8,12 @@
 namespace Drupal\Core\Config;
 
 use Drupal\Core\Cache\Cache;
-use Drupal\Core\Cache\CacheBackendInterface;
+use Drupal\Core\Cache\CacheFactoryInterface;
 
 /**
  * Defines the cached storage.
  *
- * The class gets another storage and a cache backend injected. It reads from
+ * The class gets another storage and the cache factory injected. It reads from
  * the cache and delegates the read to the storage on a cache miss. It also
  * handles cache invalidation.
  */
@@ -27,6 +27,13 @@ class CachedStorage implements StorageInterface, StorageCacheInterface {
   protected $storage;
 
   /**
+   * The cache factory.
+   *
+   * @var \Drupal\Core\Cache\CacheFactoryInterface
+   */
+  protected $cacheFactory;
+
+  /**
    * The instantiated Cache backend.
    *
    * @var \Drupal\Core\Cache\CacheBackendInterface
@@ -45,12 +52,20 @@ class CachedStorage implements StorageInterface, StorageCacheInterface {
    *
    * @param \Drupal\Core\Config\StorageInterface $storage
    *   A configuration storage to be cached.
-   * @param \Drupal\Core\Cache\CacheBackendInterface $cache
-   *   A cache backend instance to use for caching.
+   * @param \Drupal\Core\Cache\CacheFactoryInterface $cache_factory
+   *   A cache factory used for getting cache backends.
    */
-  public function __construct(StorageInterface $storage, CacheBackendInterface $cache) {
+  public function __construct(StorageInterface $storage, CacheFactoryInterface $cache_factory) {
     $this->storage = $storage;
-    $this->cache = $cache;
+    $this->cacheFactory = $cache_factory;
+    $collection = $this->getCollectionName();
+    if ($collection == StorageInterface::DEFAULT_COLLECTION) {
+      $bin = 'config';
+    }
+    else {
+      $bin = 'config_' . str_replace('.', '_', $collection);
+    }
+    $this->cache = $this->cacheFactory->get($bin);
   }
 
   /**
@@ -238,4 +253,29 @@ public function deleteAll($prefix = '') {
   public function resetListCache() {
     $this->findByPrefixCache = array();
   }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function createCollection($collection) {
+    return new static(
+      $this->storage->createCollection($collection),
+      $this->cacheFactory
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getAllCollectionNames() {
+    return $this->storage->getAllCollectionNames();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getCollectionName() {
+    return $this->storage->getCollectionName();
+  }
+
 }
diff --git a/core/lib/Drupal/Core/Config/ConfigCollectionNamesEvent.php b/core/lib/Drupal/Core/Config/ConfigCollectionNamesEvent.php
new file mode 100644
index 0000000..3633d43
--- /dev/null
+++ b/core/lib/Drupal/Core/Config/ConfigCollectionNamesEvent.php
@@ -0,0 +1,59 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\Config\ConfigCollectionNamesEvent.
+ */
+
+namespace Drupal\Core\Config;
+
+use Symfony\Component\EventDispatcher\Event;
+
+/**
+ * Wraps a configuration event for event listeners.
+ */
+class ConfigCollectionNamesEvent extends Event {
+
+  /**
+   * Configuration collection names.
+   *
+   * @var array
+   */
+  protected $collections = array();
+
+  /**
+   * Adds names to the list of possible collections.
+   *
+   * @param array $collections
+   *   Collection names to add.
+   */
+  public function addCollectionNames(array $collections) {
+    $this->collections = array_merge($this->collections, $collections);
+  }
+
+  /**
+   * Adds a name to the list of possible collections.
+   *
+   * @param string $collection
+   *   Collection name to add.
+   */
+  public function addCollectionName($collection) {
+    $this->addCollectionNames(array($collection));
+  }
+
+  /**
+   * Gets the list of possible collection names.
+   *
+   * @return array
+   *   The list of possible collection names.
+   */
+  public function getCollectionNames($include_default = TRUE) {
+    sort($this->collections);
+    $collections = array_unique($this->collections);
+    if ($include_default) {
+      array_unshift($collections, StorageInterface::DEFAULT_COLLECTION);
+    }
+    return $collections;
+  }
+
+}
diff --git a/core/lib/Drupal/Core/Config/ConfigEvents.php b/core/lib/Drupal/Core/Config/ConfigEvents.php
index a5c8b57..2d12a50 100644
--- a/core/lib/Drupal/Core/Config/ConfigEvents.php
+++ b/core/lib/Drupal/Core/Config/ConfigEvents.php
@@ -50,4 +50,11 @@
    */
   const IMPORT = 'config.importer.import';
 
+  /**
+   * Name of event fired to discover all the possible configuration collections.
+   *
+   * @see \Drupal\Core\Config\ConfigInstaller::installDefaultConfig()
+   */
+  const COLLECTION_NAMES = 'config.collection_names';
+
 }
diff --git a/core/lib/Drupal/Core/Config/ConfigImporter.php b/core/lib/Drupal/Core/Config/ConfigImporter.php
index 6b36913..716a6ae 100644
--- a/core/lib/Drupal/Core/Config/ConfigImporter.php
+++ b/core/lib/Drupal/Core/Config/ConfigImporter.php
@@ -185,7 +185,9 @@ public function __construct(StorageComparerInterface $storage_comparer, EventDis
     $this->moduleHandler = $module_handler;
     $this->themeHandler = $theme_handler;
     $this->stringTranslation = $string_translation;
-    $this->processedConfiguration = $this->storageComparer->getEmptyChangelist();
+    foreach ($this->storageComparer->getAllCollectionNames() as $collection) {
+      $this->processedConfiguration[$collection] = $this->storageComparer->getEmptyChangelist();
+    }
     $this->processedExtensions = $this->getEmptyExtensionsProcessedList();
   }
 
@@ -227,7 +229,9 @@ public function getStorageComparer() {
    */
   public function reset() {
     $this->storageComparer->reset();
-    $this->processedConfiguration = $this->storageComparer->getEmptyChangelist();
+    foreach ($this->storageComparer->getAllCollectionNames() as $collection) {
+      $this->processedConfiguration[$collection] = $this->storageComparer->getEmptyChangelist();
+    }
     $this->processedExtensions = $this->getEmptyExtensionsProcessedList();
     $this->createExtensionChangelist();
     $this->validated = FALSE;
@@ -257,16 +261,13 @@ protected function getEmptyExtensionsProcessedList() {
   /**
    * Checks if there are any unprocessed configuration changes.
    *
-   * @param array $ops
-   *   The operations to check for changes. Defaults to all operations, i.e.
-   *   array('delete', 'create', 'update', 'rename').
-   *
    * @return bool
    *   TRUE if there are changes to process and FALSE if not.
    */
-  public function hasUnprocessedConfigurationChanges($ops = array('delete', 'create', 'rename', 'update')) {
-    foreach ($ops as $op) {
-      if (count($this->getUnprocessedConfiguration($op))) {
+  public function hasUnprocessedConfigurationChanges() {
+    foreach ($this->storageComparer->getAllCollectionNames() as $collection)
+    foreach (array('delete', 'create', 'rename', 'update') as $op) {
+      if (count($this->getUnprocessedConfiguration($op, $collection))) {
         return TRUE;
       }
     }
@@ -276,23 +277,29 @@ public function hasUnprocessedConfigurationChanges($ops = array('delete', 'creat
   /**
    * Gets list of processed changes.
    *
+   * @param string $collection
+   *   (optional) The configuration collection to get processed changes for.
+   *   Defaults to the default collection.
+   *
    * @return array
    *   An array containing a list of processed changes.
    */
-  public function getProcessedConfiguration() {
-    return $this->processedConfiguration;
+  public function getProcessedConfiguration($collection = StorageInterface::DEFAULT_COLLECTION) {
+    return $this->processedConfiguration[$collection];
   }
 
   /**
    * Sets a change as processed.
    *
+   * @param string $collection
+   *   The configuration collection to set a change as processed for.
    * @param string $op
    *   The change operation performed, either delete, create, rename, or update.
    * @param string $name
    *   The name of the configuration processed.
    */
-  protected function setProcessedConfiguration($op, $name) {
-    $this->processedConfiguration[$op][] = $name;
+  protected function setProcessedConfiguration($collection, $op, $name) {
+    $this->processedConfiguration[$collection][$op][] = $name;
   }
 
   /**
@@ -301,12 +308,15 @@ protected function setProcessedConfiguration($op, $name) {
    * @param string $op
    *   The change operation to get the unprocessed list for, either delete,
    *   create, rename, or update.
+   * @param string $collection
+   *   (optional) The configuration collection to get unprocessed changes for.
+   *   Defaults to the default collection.
    *
    * @return array
    *   An array of configuration names.
    */
-  public function getUnprocessedConfiguration($op) {
-    return array_diff($this->storageComparer->getChangelist($op), $this->processedConfiguration[$op]);
+  public function getUnprocessedConfiguration($op, $collection = StorageInterface::DEFAULT_COLLECTION) {
+    return array_diff($this->storageComparer->getChangelist($op, $collection), $this->processedConfiguration[$collection][$op]);
   }
 
   /**
@@ -582,19 +592,29 @@ public function processConfigurations(array &$context) {
     // into account.
     if ($this->totalConfigurationToProcess == 0) {
       $this->storageComparer->reset();
-      foreach (array('delete', 'create', 'rename', 'update') as $op) {
-        foreach ($this->getUnprocessedConfiguration($op) as $name) {
-          $this->totalConfigurationToProcess += count($this->getUnprocessedConfiguration($op));
+      foreach ($this->storageComparer->getAllCollectionNames() as $collection) {
+        foreach (array('delete', 'create', 'rename', 'update') as $op) {
+          $this->totalConfigurationToProcess += count($this->getUnprocessedConfiguration($op, $collection));
         }
       }
     }
     $operation = $this->getNextConfigurationOperation();
     if (!empty($operation)) {
-      if ($this->checkOp($operation['op'], $operation['name'])) {
-        $this->processConfiguration($operation['op'], $operation['name']);
+      if ($this->checkOp($operation['collection'], $operation['op'], $operation['name'])) {
+        $this->processConfiguration($operation['collection'], $operation['op'], $operation['name']);
+      }
+      if ($operation['collection'] == StorageInterface::DEFAULT_COLLECTION) {
+        $context['message'] = $this->t('Synchronizing configuration: @op @name.', array('@op' => $operation['op'], '@name' => $operation['name']));
+      }
+      else {
+        $context['message'] = $this->t('Synchronizing configuration: @op @name in @collection.', array('@op' => $operation['op'], '@name' => $operation['name'], '@collection' => $operation['collection']));
+      }
+      $processed_count = 0;
+      foreach ($this->storageComparer->getAllCollectionNames() as $collection) {
+        foreach (array('delete', 'create', 'rename', 'update') as $op) {
+          $processed_count += count($this->processedConfiguration[$collection][$op]);
+        }
       }
-      $context['message'] = t('Synchronizing configuration: @op @name.', array('@op' => $operation['op'], '@name' => $operation['name']));
-      $processed_count = count($this->processedConfiguration['create']) + count($this->processedConfiguration['delete']) + count($this->processedConfiguration['update']);
       $context['finished'] = $processed_count / $this->totalConfigurationToProcess;
     }
     else {
@@ -658,13 +678,16 @@ protected function getNextExtensionOperation() {
   protected function getNextConfigurationOperation() {
     // The order configuration operations is processed is important. Deletes
     // have to come first so that recreates can work.
-    foreach (array('delete', 'create', 'rename', 'update') as $op) {
-      $config_names = $this->getUnprocessedConfiguration($op);
-      if (!empty($config_names)) {
-        return array(
-          'op' => $op,
-          'name' => array_shift($config_names),
-        );
+    foreach ($this->storageComparer->getAllCollectionNames() as $collection) {
+      foreach (array('delete', 'create', 'rename', 'update') as $op) {
+        $config_names = $this->getUnprocessedConfiguration($op, $collection);
+        if (!empty($config_names)) {
+          return array(
+            'op' => $op,
+            'name' => array_shift($config_names),
+            'collection' => $collection,
+          );
+        }
       }
     }
     return FALSE;
@@ -708,6 +731,8 @@ public function validate() {
   /**
    * Processes a configuration change.
    *
+   * @param string $collection
+   *   The configuration collection to process changes for.
    * @param string $op
    *   The change operation.
    * @param string $name
@@ -718,17 +743,21 @@ public function validate() {
    *   set, otherwise the exception message is logged and the configuration
    *   is skipped.
    */
-  protected function processConfiguration($op, $name) {
+  protected function processConfiguration($collection, $op, $name) {
     try {
-      if (!$this->importInvokeOwner($op, $name)) {
-        $this->importConfig($op, $name);
+      $processed = FALSE;
+      if ($this->configManager->supportsConfigurationEntities($collection)) {
+        $processed = $this->importInvokeOwner($collection, $op, $name);
+      }
+      if (!$processed) {
+        $this->importConfig($collection, $op, $name);
       }
     }
     catch (\Exception $e) {
       $this->logError($this->t('Unexpected error during import with operation @op for @name: @message', array('@op' => $op, '@name' => $name, '@message' => $e->getMessage())));
       // Error for that operation was logged, mark it as processed so that
       // the import can continue.
-      $this->setProcessedConfiguration($op, $name);
+      $this->setProcessedConfiguration($collection, $op, $name);
     }
   }
 
@@ -765,7 +794,7 @@ protected function processExtension($type, $op, $name) {
       // the default or admin theme is change this will be picked up whilst
       // processing configuration.
       if ($op == 'disable' && $this->processedSystemTheme === FALSE) {
-        $this->importConfig('update', 'system.theme');
+        $this->importConfig(StorageInterface::DEFAULT_COLLECTION, 'update', 'system.theme');
         $this->configManager->getConfigFactory()->reset('system.theme');
         $this->processedSystemTheme = TRUE;
       }
@@ -785,6 +814,8 @@ protected function processExtension($type, $op, $name) {
    * This method checks that the operation is still valid before processing a
    * configuration change.
    *
+   * @param string $collection
+   *   The configuration collection.
    * @param string $op
    *   The change operation.
    * @param string $name
@@ -795,10 +826,10 @@ protected function processExtension($type, $op, $name) {
    * @return bool
    *   TRUE is to continue processing, FALSE otherwise.
    */
-  protected function checkOp($op, $name) {
+  protected function checkOp($collection, $op, $name) {
     if ($op == 'rename') {
       $names = $this->storageComparer->extractRenameNames($name);
-      $target_exists = $this->storageComparer->getTargetStorage()->exists($names['new_name']);
+      $target_exists = $this->storageComparer->getTargetStorage($collection)->exists($names['new_name']);
       if ($target_exists) {
         // If the target exists, the rename has already occurred as the
         // result of a secondary configuration write. Change the operation
@@ -810,13 +841,13 @@ protected function checkOp($op, $name) {
       }
       return TRUE;
     }
-    $target_exists = $this->storageComparer->getTargetStorage()->exists($name);
+    $target_exists = $this->storageComparer->getTargetStorage($collection)->exists($name);
     switch ($op) {
       case 'delete':
         if (!$target_exists) {
           // The configuration has already been deleted. For example, a field
           // is automatically deleted if all the instances are.
-          $this->setProcessedConfiguration($op, $name);
+          $this->setProcessedConfiguration($collection, $op, $name);
           return FALSE;
         }
         break;
@@ -833,7 +864,7 @@ protected function checkOp($op, $name) {
             $this->logError($this->t('Deleted and replaced configuration entity "@name"', array('@name' => $name)));
           }
           else {
-            $this->storageComparer->getTargetStorage()->delete($name);
+            $this->storageComparer->getTargetStorage($collection)->delete($name);
             $this->logError($this->t('Deleted and replaced configuration "@name"', array('@name' => $name)));
           }
           return TRUE;
@@ -846,7 +877,7 @@ protected function checkOp($op, $name) {
           // Mark as processed so that the synchronisation continues. Once the
           // the current synchronisation is complete it will show up as a
           // create.
-          $this->setProcessedConfiguration($op, $name);
+          $this->setProcessedConfiguration($collection, $op, $name);
           return FALSE;
         }
         break;
@@ -857,22 +888,24 @@ protected function checkOp($op, $name) {
   /**
    * Writes a configuration change from the source to the target storage.
    *
+   * @param string $collection
+   *   The configuration collection.
    * @param string $op
    *   The change operation.
    * @param string $name
    *   The name of the configuration to process.
    */
-  protected function importConfig($op, $name) {
-    $config = new Config($name, $this->storageComparer->getTargetStorage(), $this->eventDispatcher, $this->typedConfigManager);
+  protected function importConfig($collection, $op, $name) {
+    $config = new Config($name, $this->storageComparer->getTargetStorage($collection), $this->eventDispatcher, $this->typedConfigManager);
     if ($op == 'delete') {
       $config->delete();
     }
     else {
-      $data = $this->storageComparer->getSourceStorage()->read($name);
+      $data = $this->storageComparer->getSourceStorage($collection)->read($name);
       $config->setData($data ? $data : array());
       $config->save();
     }
-    $this->setProcessedConfiguration($op, $name);
+    $this->setProcessedConfiguration($collection, $op, $name);
   }
 
   /**
@@ -883,6 +916,8 @@ protected function importConfig($op, $name) {
    *
    * @todo Add support for other extension types; e.g., themes etc.
    *
+   * @param string $collection
+   *   The configuration collection.
    * @param string $op
    *   The change operation to get the unprocessed list for, either delete,
    *   create, rename, or update.
@@ -897,21 +932,21 @@ protected function importConfig($op, $name) {
    *   TRUE if the configuration was imported as a configuration entity. FALSE
    *   otherwise.
    */
-  protected function importInvokeOwner($op, $name) {
+  protected function importInvokeOwner($collection, $op, $name) {
     // Renames are handled separately.
     if ($op == 'rename') {
-      return $this->importInvokeRename($name);
+      return $this->importInvokeRename($collection, $name);
     }
     // Validate the configuration object name before importing it.
     // Config::validateName($name);
     if ($entity_type = $this->configManager->getEntityTypeIdByName($name)) {
-      $old_config = new Config($name, $this->storageComparer->getTargetStorage(), $this->eventDispatcher, $this->typedConfigManager);
-      if ($old_data = $this->storageComparer->getTargetStorage()->read($name)) {
+      $old_config = new Config($name, $this->storageComparer->getTargetStorage($collection), $this->eventDispatcher, $this->typedConfigManager);
+      if ($old_data = $this->storageComparer->getTargetStorage($collection)->read($name)) {
         $old_config->initWithData($old_data);
       }
 
-      $data = $this->storageComparer->getSourceStorage()->read($name);
-      $new_config = new Config($name, $this->storageComparer->getTargetStorage(), $this->eventDispatcher, $this->typedConfigManager);
+      $data = $this->storageComparer->getSourceStorage($collection)->read($name);
+      $new_config = new Config($name, $this->storageComparer->getTargetStorage($collection), $this->eventDispatcher, $this->typedConfigManager);
       if ($data !== FALSE) {
         $new_config->setData($data);
       }
@@ -924,7 +959,7 @@ protected function importInvokeOwner($op, $name) {
         throw new EntityStorageException(String::format('The entity storage "@storage" for the "@entity_type" entity type does not support imports', array('@storage' => get_class($entity_storage), '@entity_type' => $entity_type)));
       }
       $entity_storage->$method($name, $new_config, $old_config);
-      $this->setProcessedConfiguration($op, $name);
+      $this->setProcessedConfiguration($collection, $op, $name);
       return TRUE;
     }
     return FALSE;
@@ -933,6 +968,8 @@ protected function importInvokeOwner($op, $name) {
   /**
    * Imports a configuration entity rename.
    *
+   * @param string $collection
+   *   The configuration collection.
    * @param string $rename_name
    *   The rename configuration name, as provided by
    *   \Drupal\Core\Config\StorageComparer::createRenameName().
@@ -943,16 +980,16 @@ protected function importInvokeOwner($op, $name) {
    *
    * @see \Drupal\Core\Config\ConfigImporter::createRenameName()
    */
-  protected function importInvokeRename($rename_name) {
+  protected function importInvokeRename($collection, $rename_name) {
     $names = $this->storageComparer->extractRenameNames($rename_name);
     $entity_type_id = $this->configManager->getEntityTypeIdByName($names['old_name']);
-    $old_config = new Config($names['old_name'], $this->storageComparer->getTargetStorage(), $this->eventDispatcher, $this->typedConfigManager);
-    if ($old_data = $this->storageComparer->getTargetStorage()->read($names['old_name'])) {
+    $old_config = new Config($names['old_name'], $this->storageComparer->getTargetStorage($collection), $this->eventDispatcher, $this->typedConfigManager);
+    if ($old_data = $this->storageComparer->getTargetStorage($collection)->read($names['old_name'])) {
       $old_config->initWithData($old_data);
     }
 
-    $data = $this->storageComparer->getSourceStorage()->read($names['new_name']);
-    $new_config = new Config($names['new_name'], $this->storageComparer->getTargetStorage(), $this->eventDispatcher, $this->typedConfigManager);
+    $data = $this->storageComparer->getSourceStorage($collection)->read($names['new_name']);
+    $new_config = new Config($names['new_name'], $this->storageComparer->getTargetStorage($collection), $this->eventDispatcher, $this->typedConfigManager);
     if ($data !== FALSE) {
       $new_config->setData($data);
     }
@@ -964,7 +1001,7 @@ protected function importInvokeRename($rename_name) {
       throw new EntityStorageException(String::format('The entity storage "@storage" for the "@entity_type" entity type does not support imports', array('@storage' => get_class($entity_storage), '@entity_type' => $entity_type_id)));
     }
     $entity_storage->importRename($names['old_name'], $new_config, $old_config);
-    $this->setProcessedConfiguration('rename', $rename_name);
+    $this->setProcessedConfiguration($collection, 'rename', $rename_name);
     return TRUE;
   }
 
diff --git a/core/lib/Drupal/Core/Config/ConfigInstaller.php b/core/lib/Drupal/Core/Config/ConfigInstaller.php
index a22907b..cea8b53 100644
--- a/core/lib/Drupal/Core/Config/ConfigInstaller.php
+++ b/core/lib/Drupal/Core/Config/ConfigInstaller.php
@@ -88,10 +88,6 @@ public function __construct(ConfigFactoryInterface $config_factory, StorageInter
    * {@inheritdoc}
    */
   public function installDefaultConfig($type, $name) {
-    // Get all default configuration owned by this extension.
-    $source_storage = $this->getSourceStorage();
-    $config_to_install = $source_storage->listAll($name . '.');
-
     $extension_path = drupal_get_path($type, $name);
     // If the extension provides configuration schema clear the definitions.
     if (is_dir($extension_path . '/' . InstallStorage::CONFIG_SCHEMA_DIRECTORY)) {
@@ -100,22 +96,61 @@ public function installDefaultConfig($type, $name) {
       $this->typedConfig->clearCachedDefinitions();
     }
 
+    // Gather all the supported collection names.
+    $event = new ConfigCollectionNamesEvent();
+    $this->eventDispatcher->dispatch(ConfigEvents::COLLECTION_NAMES, $event);
+    $collections = $event->getCollectionNames();
+
+    $old_state = $this->configFactory->getOverrideState();
+    $this->configFactory->setOverrideState(FALSE);
+
+    // Read enabled extensions directly from configuration to avoid circular
+    // dependencies with ModuleHandler and ThemeHandler.
+    $extension_config = $this->configFactory->get('core.extension');
+    $enabled_extensions = array_keys((array) $extension_config->get('module'));
+    $enabled_extensions += array_keys((array) $extension_config->get('theme'));
+
+    foreach ($collections as $collection) {
+      $config_to_install = $this->listDefaultConfigCollection($collection, $type, $name, $enabled_extensions);
+      if (!empty($config_to_install)) {
+        $this->createConfiguration($collection, $config_to_install);
+      }
+    }
+    $this->configFactory->setOverrideState($old_state);
+    // Reset all the static caches and list caches.
+    $this->configFactory->reset();
+  }
+
+  /**
+   * Installs default configuration for a particular collection.
+   *
+   * @param string $collection
+   *  The configuration collection to install.
+   * @param string $type
+   *   The extension type; e.g., 'module' or 'theme'.
+   * @param string $name
+   *   The name of the module or theme to install default configuration for.
+   * @param array $enabled_extensions
+   *   A list of all the currently enabled modules and themes.
+   *
+   * @return array
+   *   The list of configuration objects to create.
+   */
+  protected function listDefaultConfigCollection($collection, $type, $name, array $enabled_extensions) {
+    // Get all default configuration owned by this extension.
+    $source_storage = $this->getSourceStorage($collection);
+    $config_to_install = $source_storage->listAll($name . '.');
+
     // If not installing the core base system default configuration, work out if
     // this extension provides default configuration for any other enabled
     // extensions.
+    $extension_path = drupal_get_path($type, $name);
     if ($type !== 'core' && is_dir($extension_path . '/' . InstallStorage::CONFIG_INSTALL_DIRECTORY)) {
-      $enabled_extensions = $other_module_config = array();
-      $default_storage = new FileStorage($extension_path . '/' . InstallStorage::CONFIG_INSTALL_DIRECTORY);
+      $default_storage = new FileStorage($extension_path . '/' . InstallStorage::CONFIG_INSTALL_DIRECTORY, $collection);
       $other_module_config = array_filter($default_storage->listAll(), function ($value) use ($name) {
         return !preg_match('/^' . $name . '\./', $value);
       });
 
-      // Read enabled extensions directly from configuration to avoid circular
-      // dependencies with ModuleHandler and ThemeHandler.
-      $extension_config = $this->configFactory->get('core.extension');
-      $enabled_extensions += array_keys((array) $extension_config->get('module'));
-      $enabled_extensions += array_keys((array) $extension_config->get('theme'));
-
       $other_module_config = array_filter($other_module_config, function ($config_name) use ($enabled_extensions) {
         $provider = Unicode::substr($config_name, 0, strpos($config_name, '.'));
         return in_array($provider, $enabled_extensions);
@@ -124,63 +159,92 @@ public function installDefaultConfig($type, $name) {
       $config_to_install = array_merge($config_to_install, $other_module_config);
     }
 
-    if (!empty($config_to_install)) {
-      // Order the configuration to install in the order of dependencies.
-      $data = $source_storage->readMultiple($config_to_install);
+    return $config_to_install;
+  }
+
+  /**
+   * Creates configuration in a collection based on the provided list.
+   *
+   * @param string $collection
+   *   The configuration collection.
+   * @param array $config_to_install
+   *   A list of configuration object names to create.
+   */
+  protected function createConfiguration($collection, array $config_to_install) {
+    // Order the configuration to install in the order of dependencies.
+    $data = $this->getSourceStorage($collection)->readMultiple($config_to_install);
+    $config_entity_support = $this->configManager->supportsConfigurationEntities($collection);
+    if ($config_entity_support) {
       $dependency_manager = new ConfigDependencyManager();
-      $sorted_config = $dependency_manager
+      $config_to_install = $dependency_manager
         ->setData($data)
         ->sortAll();
+    }
 
-      $old_state = $this->configFactory->getOverrideState();
-      $this->configFactory->setOverrideState(FALSE);
+    // Remove configuration that already exists in the active storage.
+    $config_to_install = array_diff($config_to_install, $this->getActiveStorage($collection)->listAll());
 
-      // Remove configuration that already exists in the active storage.
-      $sorted_config = array_diff($sorted_config, $this->activeStorage->listAll());
+    foreach ($config_to_install as $name) {
+      $new_config = new Config($name, $this->getActiveStorage($collection), $this->eventDispatcher, $this->typedConfig);
+      if ($data[$name] !== FALSE) {
+        $new_config->setData($data[$name]);
+      }
+      if ($config_entity_support && $entity_type = $this->configManager->getEntityTypeIdByName($name)) {
 
-      foreach ($sorted_config as $name) {
-        $new_config = new Config($name, $this->activeStorage, $this->eventDispatcher, $this->typedConfig);
-        if ($data[$name] !== FALSE) {
-          $new_config->setData($data[$name]);
+        // If we are syncing do not create configuration entities. Pluggable
+        // configuration entities can have dependencies on modules that are
+        // not yet enabled. This approach means that any code that expects
+        // default configuration entities to exist will be unstable after the
+        // module has been enabled and before the config entity has been
+        // imported.
+        if ($this->isSyncing) {
+          continue;
         }
-        if ($entity_type = $this->configManager->getEntityTypeIdByName($name)) {
-
-          // If we are syncing do not create configuration entities. Pluggable
-          // configuration entities can have dependencies on modules that are
-          // not yet enabled. This approach means that any code that expects
-          // default configuration entities to exist will be unstable after the
-          // module has been enabled and before the config entity has been
-          // imported.
-          if ($this->isSyncing) {
-            continue;
-          }
-          $entity_storage = $this->configManager
-            ->getEntityManager()
-            ->getStorage($entity_type);
-          // It is possible that secondary writes can occur during configuration
-          // creation. Updates of such configuration are allowed.
-          if ($this->activeStorage->exists($name)) {
-            $id = $entity_storage->getIDFromConfigName($name, $entity_storage->getEntityType()->getConfigPrefix());
-            $entity = $entity_storage->load($id);
-            foreach ($new_config->get() as $property => $value) {
-              $entity->set($property, $value);
-            }
-            $entity->save();
-          }
-          else {
-            $entity_storage
-              ->create($new_config->get())
-              ->save();
+        $entity_storage = $this->configManager
+          ->getEntityManager()
+          ->getStorage($entity_type);
+        // It is possible that secondary writes can occur during configuration
+        // creation. Updates of such configuration are allowed.
+        if ($this->getActiveStorage($collection)->exists($name)) {
+          $id = $entity_storage->getIDFromConfigName($name, $entity_storage->getEntityType()->getConfigPrefix());
+          $entity = $entity_storage->load($id);
+          foreach ($new_config->get() as $property => $value) {
+            $entity->set($property, $value);
           }
+          $entity->save();
         }
         else {
-          $new_config->save();
+          $entity_storage
+            ->create($new_config->get())
+            ->save();
         }
       }
+      else {
+        $new_config->save();
+      }
+    }
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function installCollectionDefaultConfig($collection) {
+    $config_to_install = $this->getSourceStorage($collection)->listAll();
+    $extension_config = $this->configFactory->get('core.extension');
+    $enabled_extensions = array_keys((array) $extension_config->get('module'));
+    $enabled_extensions += array_keys((array) $extension_config->get('theme'));
+    $config_to_install = array_filter($config_to_install, function ($config_name) use ($enabled_extensions) {
+      $provider = Unicode::substr($config_name, 0, strpos($config_name, '.'));
+      return in_array($provider, $enabled_extensions);
+    });
+    if (!empty($config_to_install)) {
+      $old_state = $this->configFactory->getOverrideState();
+      $this->configFactory->setOverrideState(FALSE);
+      $this->createConfiguration($collection, $config_to_install);
       $this->configFactory->setOverrideState($old_state);
+      // Reset all the static caches and list caches.
+      $this->configFactory->reset();
     }
-    // Reset all the static caches and list caches.
-    $this->configFactory->reset();
   }
 
   /**
@@ -202,19 +266,43 @@ public function resetSourceStorage() {
   /**
    * Gets the configuration storage that provides the default configuration.
    *
+   * @param string $collection
+   *   (optional) The configuration collection. Defaults to the default
+   *   collection.
+   *
    * @return \Drupal\Core\Config\StorageInterface
    *   The configuration storage that provides the default configuration.
    */
-  public function getSourceStorage() {
+  public function getSourceStorage($collection = StorageInterface::DEFAULT_COLLECTION) {
     if (!isset($this->sourceStorage)) {
       // Default to using the ExtensionInstallStorage which searches extension's
       // config directories for default configuration.
-      $this->sourceStorage = new ExtensionInstallStorage($this->activeStorage);
+      $this->sourceStorage = new ExtensionInstallStorage($this->activeStorage, InstallStorage::CONFIG_INSTALL_DIRECTORY, $collection);
+    }
+    if ($this->sourceStorage->getCollectionName() != $collection) {
+      $this->sourceStorage = $this->sourceStorage->createCollection($collection);
     }
     return $this->sourceStorage;
   }
 
   /**
+   * Gets the configuration storage that provides the active configuration.
+   *
+   * @param string $collection
+   *   (optional) The configuration collection. Defaults to the default
+   *   collection.
+   *
+   * @return \Drupal\Core\Config\StorageInterface
+   *   The configuration storage that provides the default configuration.
+   */
+  protected function getActiveStorage($collection = StorageInterface::DEFAULT_COLLECTION) {
+    if ($this->activeStorage->getCollectionName() != $collection) {
+      $this->activeStorage = $this->activeStorage->createCollection($collection);
+    }
+    return $this->activeStorage;
+  }
+
+  /**
    * {@inheritdoc}
    */
   public function setSyncing($status) {
diff --git a/core/lib/Drupal/Core/Config/ConfigInstallerInterface.php b/core/lib/Drupal/Core/Config/ConfigInstallerInterface.php
index efa3d54..642044e 100644
--- a/core/lib/Drupal/Core/Config/ConfigInstallerInterface.php
+++ b/core/lib/Drupal/Core/Config/ConfigInstallerInterface.php
@@ -38,6 +38,19 @@
   public function installDefaultConfig($type, $name);
 
   /**
+   * Installs all default configuration in the specified collection.
+   *
+   * The function is useful if the site needs to respond to an event that has
+   * just created another collection and we need to check all the installed
+   * extensions for any matching configuration. For example, if a language has
+   * just been created.
+   *
+   * @param string $collection
+   *   The configuration collection.
+   */
+  public function installCollectionDefaultConfig($collection);
+
+  /**
    * Sets the configuration storage that provides the default configuration.
    *
    * @param \Drupal\Core\Config\StorageInterface $storage
diff --git a/core/lib/Drupal/Core/Config/ConfigManager.php b/core/lib/Drupal/Core/Config/ConfigManager.php
index 6faa23e..7d33de6 100644
--- a/core/lib/Drupal/Core/Config/ConfigManager.php
+++ b/core/lib/Drupal/Core/Config/ConfigManager.php
@@ -100,7 +100,11 @@ public function getConfigFactory() {
   /**
    * {@inheritdoc}
    */
-  public function diff(StorageInterface $source_storage, StorageInterface $target_storage, $source_name, $target_name = NULL) {
+  public function diff(StorageInterface $source_storage, StorageInterface $target_storage, $source_name, $target_name = NULL, $collection = StorageInterface::DEFAULT_COLLECTION) {
+    if ($collection != StorageInterface::DEFAULT_COLLECTION) {
+      $source_storage = $source_storage->createCollection($collection);
+      $target_storage = $target_storage->createCollection($collection);
+    }
     if (!isset($target_name)) {
       $target_name = $source_name;
     }
@@ -131,10 +135,23 @@ public function diff(StorageInterface $source_storage, StorageInterface $target_
    * {@inheritdoc}
    */
   public function createSnapshot(StorageInterface $source_storage, StorageInterface $snapshot_storage) {
+    // Empty the snapshot of all configuration.
     $snapshot_storage->deleteAll();
+    foreach ($snapshot_storage->getAllCollectionNames() as $collection) {
+      $snapshot_collection = $snapshot_storage->createCollection($collection);
+      $snapshot_collection->deleteAll();
+    }
     foreach ($source_storage->listAll() as $name) {
       $snapshot_storage->write($name, $source_storage->read($name));
     }
+    // Copy collections as well.
+    foreach ($source_storage->getAllCollectionNames() as $collection) {
+      $source_collection = $source_storage->createCollection($collection);
+      $snapshot_collection = $snapshot_storage->createCollection($collection);
+      foreach ($source_collection->listAll() as $name) {
+        $snapshot_collection->write($name, $source_collection->read($name));
+      }
+    }
   }
 
   /**
@@ -156,6 +173,13 @@ public function uninstall($type, $name) {
     foreach ($config_names as $config_name) {
       $this->configFactory->get($config_name)->delete();
     }
+
+    // Remove any matching configuration from collections.
+    foreach ($this->activeStorage->getAllCollectionNames() as $collection) {
+      $collection_storage = $this->activeStorage->createCollection($collection);
+      $collection_storage->deleteAll($name . '.');
+    }
+
     $schema_dir = drupal_get_path($type, $name) . '/' . InstallStorage::CONFIG_SCHEMA_DIRECTORY;
     if (is_dir($schema_dir)) {
       // Refresh the schema cache if uninstalling an extension that provides
@@ -216,4 +240,10 @@ public function findConfigEntityDependentsAsEntities($type, array $names) {
     return $entities_to_return;
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public function supportsConfigurationEntities($collection) {
+    return $collection == StorageInterface::DEFAULT_COLLECTION;
+  }
 }
diff --git a/core/lib/Drupal/Core/Config/ConfigManagerInterface.php b/core/lib/Drupal/Core/Config/ConfigManagerInterface.php
index 1d35637..3be67c8 100644
--- a/core/lib/Drupal/Core/Config/ConfigManagerInterface.php
+++ b/core/lib/Drupal/Core/Config/ConfigManagerInterface.php
@@ -51,13 +51,16 @@ public function getConfigFactory();
    * @param string $target_name
    *   (optional) The name of the configuration object in the target storage.
    *   If omitted, the source name is used.
+   * @param string $collection
+   *   (optional) The configuration collection name. Defaults to the default
+   *   collection.
    *
    * @return core/lib/Drupal/Component/Diff
    *   A formatted string showing the difference between the two storages.
    *
    * @todo Make renderer injectable
    */
-  public function diff(StorageInterface $source_storage, StorageInterface $target_storage, $source_name, $target_name = NULL);
+  public function diff(StorageInterface $source_storage, StorageInterface $target_storage, $source_name, $target_name = NULL, $collection = StorageInterface::DEFAULT_COLLECTION);
 
   /**
    * Creates a configuration snapshot following a successful import.
@@ -109,5 +112,15 @@ public function findConfigEntityDependents($type, array $names);
    */
   public function findConfigEntityDependentsAsEntities($type, array $names);
 
+  /**
+   * Determines if the provided collection supports configuration entities.
+   *
+   * @param string $collection
+   *   The collection to check.
+   *
+   * @return bool
+   *   TRUE if the collection support configuration entities, FALSE if not.
+   */
+  public function supportsConfigurationEntities($collection);
 
 }
diff --git a/core/lib/Drupal/Core/Config/DatabaseStorage.php b/core/lib/Drupal/Core/Config/DatabaseStorage.php
index 11ab691..99c638e 100644
--- a/core/lib/Drupal/Core/Config/DatabaseStorage.php
+++ b/core/lib/Drupal/Core/Config/DatabaseStorage.php
@@ -38,6 +38,13 @@ class DatabaseStorage implements StorageInterface {
   protected $options = array();
 
   /**
+   * The storage collection.
+   *
+   * @var string
+   */
+  protected $collection = StorageInterface::DEFAULT_COLLECTION;
+
+  /**
    * Constructs a new DatabaseStorage.
    *
    * @param \Drupal\Core\Database\Connection $connection
@@ -46,11 +53,15 @@ class DatabaseStorage implements StorageInterface {
    *   A database table name to store configuration data in.
    * @param array $options
    *   (optional) Any additional database connection options to use in queries.
+   * @param string $collection
+   *   (optional) The collection to store configuration in. Defaults to the
+   *   default collection.
    */
-  public function __construct(Connection $connection, $table, array $options = array()) {
+  public function __construct(Connection $connection, $table, array $options = array(), $collection = StorageInterface::DEFAULT_COLLECTION) {
     $this->connection = $connection;
     $this->table = $table;
     $this->options = $options;
+    $this->collection = $collection;
   }
 
   /**
@@ -58,7 +69,8 @@ public function __construct(Connection $connection, $table, array $options = arr
    */
   public function exists($name) {
     try {
-      return (bool) $this->connection->queryRange('SELECT 1 FROM {' . $this->connection->escapeTable($this->table) . '} WHERE name = :name', 0, 1, array(
+      return (bool) $this->connection->queryRange('SELECT 1 FROM {' . $this->connection->escapeTable($this->table) . '} WHERE collection = :collection AND name = :name', 0, 1, array(
+        ':collection' => $this->collection,
         ':name' => $name,
       ), $this->options)->fetchField();
     }
@@ -75,7 +87,7 @@ public function exists($name) {
   public function read($name) {
     $data = FALSE;
     try {
-      $raw = $this->connection->query('SELECT data FROM {' . $this->connection->escapeTable($this->table) . '} WHERE name = :name', array(':name' => $name), $this->options)->fetchField();
+      $raw = $this->connection->query('SELECT data FROM {' . $this->connection->escapeTable($this->table) . '} WHERE collection = :collection AND name = :name', array(':collection' => $this->collection, ':name' => $name), $this->options)->fetchField();
       if ($raw !== FALSE) {
         $data = $this->decode($raw);
       }
@@ -93,7 +105,7 @@ public function read($name) {
   public function readMultiple(array $names) {
     $list = array();
     try {
-      $list = $this->connection->query('SELECT name, data FROM {' . $this->connection->escapeTable($this->table) . '} WHERE name IN (:names)', array(':names' => $names), $this->options)->fetchAllKeyed();
+      $list = $this->connection->query('SELECT name, data FROM {' . $this->connection->escapeTable($this->table) . '} WHERE collection = :collection AND name IN (:names)', array(':collection' => $this->collection, ':names' => $names), $this->options)->fetchAllKeyed();
       foreach ($list as &$data) {
         $data = $this->decode($data);
       }
@@ -136,7 +148,7 @@ public function write($name, array $data) {
   protected function doWrite($name, $data) {
     $options = array('return' => Database::RETURN_AFFECTED) + $this->options;
     return (bool) $this->connection->merge($this->table, $options)
-      ->key('name', $name)
+      ->keys(array('collection', 'name'), array($this->collection, $name))
       ->fields(array('data' => $data))
       ->execute();
   }
@@ -176,8 +188,15 @@ protected static function schemaDefinition() {
     $schema = array(
       'description' => 'The base table for configuration data.',
       'fields' => array(
+        'collection' => array(
+          'description' => 'Primary Key: Config object collection.',
+          'type' => 'varchar',
+          'length' => 255,
+          'not null' => TRUE,
+          'default' => '',
+        ),
         'name' => array(
-          'description' => 'Primary Key: Unique config object name.',
+          'description' => 'Primary Key: Config object name.',
           'type' => 'varchar',
           'length' => 255,
           'not null' => TRUE,
@@ -190,7 +209,7 @@ protected static function schemaDefinition() {
           'size' => 'big',
         ),
       ),
-      'primary key' => array('name'),
+      'primary key' => array('collection', 'name'),
     );
     return $schema;
   }
@@ -205,6 +224,7 @@ protected static function schemaDefinition() {
   public function delete($name) {
     $options = array('return' => Database::RETURN_AFFECTED) + $this->options;
     return (bool) $this->connection->delete($this->table, $options)
+      ->condition('collection', $this->collection)
       ->condition('name', $name)
       ->execute();
   }
@@ -220,6 +240,7 @@ public function rename($name, $new_name) {
     return (bool) $this->connection->update($this->table, $options)
       ->fields(array('name' => $new_name))
       ->condition('name', $name)
+      ->condition('collection', $this->collection)
       ->execute();
   }
 
@@ -246,7 +267,8 @@ public function decode($raw) {
    */
   public function listAll($prefix = '') {
     try {
-      return $this->connection->query('SELECT name FROM {' . $this->connection->escapeTable($this->table) . '} WHERE name LIKE :name', array(
+      return $this->connection->query('SELECT name FROM {' . $this->connection->escapeTable($this->table) . '} WHERE collection = :collection AND name LIKE :name', array(
+        ':collection' => $this->collection,
         ':name' => $this->connection->escapeLike($prefix) . '%',
       ), $this->options)->fetchCol();
     }
@@ -263,10 +285,46 @@ public function deleteAll($prefix = '') {
       $options = array('return' => Database::RETURN_AFFECTED) + $this->options;
       return (bool) $this->connection->delete($this->table, $options)
         ->condition('name', $prefix . '%', 'LIKE')
+        ->condition('collection', $this->collection)
         ->execute();
     }
     catch (\Exception $e) {
       return FALSE;
     }
   }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function createCollection($collection) {
+    return new static(
+      $this->connection,
+      $this->table,
+      $this->options,
+      $collection
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getCollectionName() {
+    return $this->collection;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getAllCollectionNames() {
+    try {
+      return $this->connection->query('SELECT DISTINCT collection FROM {' . $this->connection->escapeTable($this->table) . '} WHERE collection <> :collection ORDER by collection', array(
+        ':collection' => StorageInterface::DEFAULT_COLLECTION)
+      )->fetchCol();
+    }
+    catch (\Exception $e) {
+      return array();
+    }
+  }
+
+
 }
diff --git a/core/lib/Drupal/Core/Config/ExtensionInstallStorage.php b/core/lib/Drupal/Core/Config/ExtensionInstallStorage.php
index 813efeb..81871a7 100644
--- a/core/lib/Drupal/Core/Config/ExtensionInstallStorage.php
+++ b/core/lib/Drupal/Core/Config/ExtensionInstallStorage.php
@@ -30,11 +30,26 @@ class ExtensionInstallStorage extends InstallStorage {
    *   themes is stored.
    * @param string $directory
    *   The directory to scan in each extension to scan for files. Defaults to
-   *   'config'.
+   *   'config/install'.
+   * @param string $collection
+   *   (optional) The collection to store configuration in. Defaults to the
+   *   default collection.
    */
-  public function __construct(StorageInterface $config_storage, $directory = self::CONFIG_INSTALL_DIRECTORY) {
+  public function __construct(StorageInterface $config_storage, $directory = self::CONFIG_INSTALL_DIRECTORY, $collection = StorageInterface::DEFAULT_COLLECTION) {
     $this->configStorage = $config_storage;
     $this->directory = $directory;
+    $this->collection = $collection;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function createCollection($collection) {
+    return new static(
+      $this->configStorage,
+      $this->directory,
+      $collection
+    );
   }
 
   /**
diff --git a/core/lib/Drupal/Core/Config/FileStorage.php b/core/lib/Drupal/Core/Config/FileStorage.php
index 1dac0f4..c11a54a 100644
--- a/core/lib/Drupal/Core/Config/FileStorage.php
+++ b/core/lib/Drupal/Core/Config/FileStorage.php
@@ -17,6 +17,13 @@
 class FileStorage implements StorageInterface {
 
   /**
+   * The storage collection.
+   *
+   * @var string
+   */
+  protected $collection;
+
+  /**
    * The filesystem path for configuration objects.
    *
    * @var string
@@ -28,9 +35,13 @@ class FileStorage implements StorageInterface {
    *
    * @param string $directory
    *   A directory path to use for reading and writing of configuration files.
+   * @param string $collection
+   *   (optional) The collection to store configuration in. Defaults to the
+   *   default collection.
    */
-  public function __construct($directory) {
+  public function __construct($directory, $collection = StorageInterface::DEFAULT_COLLECTION) {
     $this->directory = $directory;
+    $this->collection = $collection;
   }
 
   /**
@@ -40,7 +51,7 @@ public function __construct($directory) {
    *   The path to the configuration file.
    */
   public function getFilePath($name) {
-    return $this->directory . '/' . $name . '.' . static::getFileExtension();
+    return $this->getCollectionDirectory() . '/' . $name . '.' . static::getFileExtension();
   }
 
   /**
@@ -57,10 +68,14 @@ public static function getFileExtension() {
    * Check if the directory exists and create it if not.
    */
   protected function ensureStorage() {
-    $success = file_prepare_directory($this->directory, FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS);
-    $success = $success && file_save_htaccess($this->directory, TRUE, TRUE);
+    $dir = $this->getCollectionDirectory();
+    $success = file_prepare_directory($dir, FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS);
+    // Only create .htaccess file in root directory.
+    if ($dir == $this->directory) {
+      $success = $success && file_save_htaccess($this->directory, TRUE, TRUE);
+    }
     if (!$success) {
-      throw new StorageException("Failed to create config directory {$this->directory}");
+      throw new StorageException('Failed to create config directory ' . $dir);
     }
     return $this;
   }
@@ -142,12 +157,22 @@ public function write($name, array $data) {
    */
   public function delete($name) {
     if (!$this->exists($name)) {
-      if (!file_exists($this->directory)) {
-        throw new StorageException($this->directory . '/ not found.');
+      $dir = $this->getCollectionDirectory();
+      if (!file_exists($dir)) {
+        throw new StorageException($dir . '/ not found.');
       }
       return FALSE;
     }
-    return drupal_unlink($this->getFilePath($name));
+    $success = drupal_unlink($this->getFilePath($name));
+
+    // If a collection is now empty remove the directory.
+    if ($success && $this->collection != StorageInterface::DEFAULT_COLLECTION) {
+      $names = $this->listAll();
+      if (empty($names)) {
+        drupal_rmdir($this->getCollectionDirectory());
+      }
+    }
+    return $success;
   }
 
   /**
@@ -186,12 +211,13 @@ public function decode($raw) {
   public function listAll($prefix = '') {
     // glob() silently ignores the error of a non-existing search directory,
     // even with the GLOB_ERR flag.
-    if (!file_exists($this->directory)) {
+    $dir = $this->getCollectionDirectory();
+    if (!file_exists($dir)) {
       return array();
     }
     $extension = '.' . static::getFileExtension();
     // \GlobIterator on Windows requires an absolute path.
-    $files = new \GlobIterator(realpath($this->directory) . '/' . $prefix . '*' . $extension);
+    $files = new \GlobIterator(realpath($dir) . '/' . $prefix . '*' . $extension);
 
     $names = array();
     foreach ($files as $file) {
@@ -215,4 +241,99 @@ public function deleteAll($prefix = '') {
 
     return $success;
   }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function createCollection($collection) {
+    return new static(
+      $this->directory,
+      $collection
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getCollectionName() {
+    return $this->collection;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getAllCollectionNames() {
+    $collections = $this->getAllCollectionNamesHelper($this->directory);
+    sort($collections);
+    return $collections;
+  }
+
+  /**
+   * Helper function for getAllCollectionNames().
+   *
+   * If the file storage has the following subdirectory structure:
+   *   ./another_collection/one
+   *   ./another_collection/two
+   *   ./collection/sub/one
+   *   ./collection/sub/two
+   * this function will return:
+   * @code
+   *   array(
+   *     'another_collection.one',
+   *     'another_collection.two',
+   *     'collection.sub.one',
+   *     'collection.sub.two',
+   *   );
+   * @endcode
+   *
+   * @param string $directory
+   *   The directory to check for sub directories. This allows this
+   *   function to be used recursively to discover all the collections in the
+   *   storage.
+   *
+   * @return array
+   *   A list of collection names contained within the provided directory.
+   */
+  protected function getAllCollectionNamesHelper($directory) {
+    $collections = array();
+    foreach (new \DirectoryIterator($directory) as $fileinfo) {
+      if ($fileinfo->isDir() && !$fileinfo->isDot()) {
+        $collection = $fileinfo->getFilename();
+        // Recursively call getAllCollectionNamesHelper() to discover if there
+        // are subdirectories. Subdirectories represent a dotted collection
+        // name.
+        $sub_collections = $this->getAllCollectionNamesHelper($directory . '/' . $collection);
+        if (!empty($sub_collections)) {
+          // Build up the collection name by concatenating the subdirectory
+          // names with the current directory name.
+          foreach ($sub_collections as $sub_collection) {
+            $collections[] = $collection . '.' . $sub_collection;
+          }
+        }
+        else {
+          // The directory has no subdirectories. Therefore add each directory
+          // to list of collections to be returned by the helper.
+          $collections[] = $collection;
+        }
+      }
+    }
+    return $collections;
+  }
+
+  /**
+   * Gets the directory for the collection.
+   *
+   * @return string
+   *   The directory for the collection.
+   */
+  protected function getCollectionDirectory() {
+    if ($this->collection == StorageInterface::DEFAULT_COLLECTION) {
+      $dir = $this->directory;
+    }
+    else {
+      $dir = $this->directory . '/' . str_replace('.', '/', $this->collection);
+    }
+    return $dir;
+  }
+
 }
diff --git a/core/lib/Drupal/Core/Config/InstallStorage.php b/core/lib/Drupal/Core/Config/InstallStorage.php
index 2db0944..e9bd690 100644
--- a/core/lib/Drupal/Core/Config/InstallStorage.php
+++ b/core/lib/Drupal/Core/Config/InstallStorage.php
@@ -51,10 +51,14 @@ class InstallStorage extends FileStorage {
    *
    * @param string $directory
    *   The directory to scan in each extension to scan for files. Defaults to
-   *   'config'.
+   *   'config/install'.
+   * @param string $collection
+   *   (optional) The collection to store configuration in. Defaults to the
+   *   default collection.
    */
-  public function __construct($directory = self::CONFIG_INSTALL_DIRECTORY) {
+  public function __construct($directory = self::CONFIG_INSTALL_DIRECTORY, $collection = StorageInterface::DEFAULT_COLLECTION) {
     $this->directory = $directory;
+    $this->collection = $collection;
   }
 
   /**
@@ -198,7 +202,7 @@ public function getComponentNames($type, array $list) {
    *   The configuration folder name for this component.
    */
   protected function getComponentFolder($type, $name) {
-    return drupal_get_path($type, $name) . '/' . $this->directory;
+    return drupal_get_path($type, $name) . '/' . $this->getCollectionDirectory();
   }
 
   /**
diff --git a/core/lib/Drupal/Core/Config/NullStorage.php b/core/lib/Drupal/Core/Config/NullStorage.php
index c66f718..5995da7 100644
--- a/core/lib/Drupal/Core/Config/NullStorage.php
+++ b/core/lib/Drupal/Core/Config/NullStorage.php
@@ -92,4 +92,26 @@ public function listAll($prefix = '') {
   public function deleteAll($prefix = '') {
     return FALSE;
   }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function createCollection($collection) {
+    // No op.
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getAllCollectionNames() {
+    return array();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getCollectionName() {
+    return '';
+  }
+
 }
diff --git a/core/lib/Drupal/Core/Config/StorageComparer.php b/core/lib/Drupal/Core/Config/StorageComparer.php
index 8a6b9f1..d19f67a 100644
--- a/core/lib/Drupal/Core/Config/StorageComparer.php
+++ b/core/lib/Drupal/Core/Config/StorageComparer.php
@@ -9,11 +9,12 @@
 
 use Drupal\Component\Utility\String;
 use Drupal\Core\Config\Entity\ConfigDependencyManager;
+use Drupal\Core\DependencyInjection\DependencySerialization;
 
 /**
  * Defines a config storage comparer.
  */
-class StorageComparer implements StorageComparerInterface {
+class StorageComparer extends DependencySerialization implements StorageComparerInterface {
 
   /**
    * The source storage used to discover configuration changes.
@@ -23,6 +24,13 @@ class StorageComparer implements StorageComparerInterface {
   protected $sourceStorage;
 
   /**
+   * The source storages keyed by collection.
+   *
+   * @var \Drupal\Core\Config\StorageInterface[]
+   */
+  protected $sourceStorages;
+
+  /**
    * The target storage used to write configuration changes.
    *
    * @var \Drupal\Core\Config\StorageInterface
@@ -30,8 +38,24 @@ class StorageComparer implements StorageComparerInterface {
   protected $targetStorage;
 
   /**
+   * The target storages keyed by collection.
+   *
+   * @var \Drupal\Core\Config\StorageInterface[]
+   */
+  protected $targetStorages;
+
+  /**
+   * The configuration manager.
+   *
+   * @var \Drupal\Core\Config\ConfigManagerInterface
+   */
+  protected $configManager;
+
+  /**
    * List of changes to between the source storage and the target storage.
    *
+   * The list is keyed by storage collection name.
+   *
    * @var array
    */
   protected $changelist;
@@ -39,6 +63,8 @@ class StorageComparer implements StorageComparerInterface {
   /**
    * Sorted list of all the configuration object names in the source storage.
    *
+   * The list is keyed by storage collection name.
+   *
    * @var array
    */
   protected $sourceNames = array();
@@ -46,6 +72,8 @@ class StorageComparer implements StorageComparerInterface {
   /**
    * Sorted list of all the configuration object names in the target storage.
    *
+   * The list is keyed by storage collection name.
+   *
    * @var array
    */
   protected $targetNames = array();
@@ -53,6 +81,8 @@ class StorageComparer implements StorageComparerInterface {
   /**
    * The source configuration data keyed by name.
    *
+   * The data is keyed by storage collection name.
+   *
    * @var array
    */
   protected $sourceData = array();
@@ -60,6 +90,8 @@ class StorageComparer implements StorageComparerInterface {
   /**
    * The target configuration data keyed by name.
    *
+   * The data is keyed by storage collection name.
+   *
    * @var array
    */
   protected $targetData = array();
@@ -71,25 +103,44 @@ class StorageComparer implements StorageComparerInterface {
    *   Storage object used to read configuration.
    * @param \Drupal\Core\Config\StorageInterface $target_storage
    *   Storage object used to write configuration.
+   * @param \Drupal\Core\Config\ConfigManagerInterface $config_manager
+   *   The configuration manager.
    */
-  public function __construct(StorageInterface $source_storage, StorageInterface $target_storage) {
+  public function __construct(StorageInterface $source_storage, StorageInterface $target_storage, ConfigManagerInterface $config_manager) {
     $this->sourceStorage = $source_storage;
     $this->targetStorage = $target_storage;
-    $this->changelist = $this->getEmptyChangelist();
+    $this->configManager = $config_manager;
+    $this->changelist[StorageInterface::DEFAULT_COLLECTION] = $this->getEmptyChangelist();
   }
 
   /**
    * {@inheritdoc}
    */
-  public function getSourceStorage() {
-    return $this->sourceStorage;
+  public function getSourceStorage($collection = StorageInterface::DEFAULT_COLLECTION) {
+    if (!isset($this->sourceStorages[$collection])) {
+      if ($collection == StorageInterface::DEFAULT_COLLECTION) {
+        $this->sourceStorages[$collection] = $this->sourceStorage;
+      }
+      else {
+        $this->sourceStorages[$collection] = $this->sourceStorage->createCollection($collection);
+      }
+    }
+    return $this->sourceStorages[$collection];
   }
 
   /**
    * {@inheritdoc}
    */
-  public function getTargetStorage() {
-    return $this->targetStorage;
+  public function getTargetStorage($collection = StorageInterface::DEFAULT_COLLECTION) {
+    if (!isset($this->targetStorages[$collection])) {
+      if ($collection == StorageInterface::DEFAULT_COLLECTION) {
+        $this->targetStorages[$collection] = $this->targetStorage;
+      }
+      else {
+        $this->targetStorages[$collection] = $this->targetStorage->createCollection($collection);
+      }
+    }
+    return $this->targetStorages[$collection];
   }
 
   /**
@@ -107,16 +158,18 @@ public function getEmptyChangelist() {
   /**
    * {@inheritdoc}
    */
-  public function getChangelist($op = NULL) {
+  public function getChangelist($op = NULL, $collection = StorageInterface::DEFAULT_COLLECTION) {
     if ($op) {
-      return $this->changelist[$op];
+      return $this->changelist[$collection][$op];
     }
-    return $this->changelist;
+    return $this->changelist[$collection];
   }
 
   /**
    * Adds changes to the changelist.
    *
+   * @param string $collection
+   *   The storage collection to add changes for.
    * @param string $op
    *   The change operation performed. Either delete, create, rename, or update.
    * @param array $changes
@@ -125,16 +178,16 @@ public function getChangelist($op = NULL) {
    *   Array to sort that can be used to sort the changelist. This array must
    *   contain all the items that are in the change list.
    */
-  protected function addChangeList($op, array $changes, array $sort_order = NULL) {
+  protected function addChangeList($collection, $op, array $changes, array $sort_order = NULL) {
     // Only add changes that aren't already listed.
-    $changes = array_diff($changes, $this->changelist[$op]);
-    $this->changelist[$op] = array_merge($this->changelist[$op], $changes);
+    $changes = array_diff($changes, $this->changelist[$collection][$op]);
+    $this->changelist[$collection][$op] = array_merge($this->changelist[$collection][$op], $changes);
     if (isset($sort_order)) {
-      $count = count($this->changelist[$op]);
+      $count = count($this->changelist[$collection][$op]);
       // Sort the changlist in the same order as the $sort_order array and
       // ensure the array is keyed from 0.
-      $this->changelist[$op] = array_values(array_intersect($sort_order, $this->changelist[$op]));
-      if ($count != count($this->changelist[$op])) {
+      $this->changelist[$collection][$op] = array_values(array_intersect($sort_order, $this->changelist[$collection][$op]));
+      if ($count != count($this->changelist[$collection][$op])) {
         throw new \InvalidArgumentException(String::format('Sorting the @op changelist should not change its length.', array('@op' => $op)));
       }
     }
@@ -144,13 +197,20 @@ protected function addChangeList($op, array $changes, array $sort_order = NULL)
    * {@inheritdoc}
    */
   public function createChangelist() {
-    $this->getAndSortConfigData();
-    $this->addChangelistCreate();
-    $this->addChangelistUpdate();
-    $this->addChangelistDelete();
-    $this->addChangelistRename();
-    $this->sourceData = NULL;
-    $this->targetData = NULL;
+    foreach ($this->getAllCollectionNames() as $collection) {
+      $this->changelist[$collection] = $this->getEmptyChangelist();
+      $this->getAndSortConfigData($collection);
+      $this->addChangelistCreate($collection);
+      $this->addChangelistUpdate($collection);
+      $this->addChangelistDelete($collection);
+      // Only collections that support configuration entities can have renames.
+      if ($this->configManager->supportsConfigurationEntities($collection)) {
+        $this->addChangelistRename($collection);
+      }
+      // Only need data whilst calculating changelists. Free up the memory.
+      $this->sourceData = NULL;
+      $this->targetData = NULL;
+    }
     return $this;
   }
 
@@ -160,10 +220,13 @@ public function createChangelist() {
    * The list of deletes is sorted so that dependencies are deleted after
    * configuration entities that depend on them. For example, field instances
    * should be deleted after fields.
+   *
+   * @param string $collection
+   *   The storage collection to operate on.
    */
-  protected function addChangelistDelete() {
-    $deletes = array_diff(array_reverse($this->targetNames), $this->sourceNames);
-    $this->addChangeList('delete', $deletes);
+  protected function addChangelistDelete($collection) {
+    $deletes = array_diff(array_reverse($this->targetNames[$collection]), $this->sourceNames[$collection]);
+    $this->addChangeList($collection, 'delete', $deletes);
   }
 
   /**
@@ -172,10 +235,13 @@ protected function addChangelistDelete() {
    * The list of creates is sorted so that dependencies are created before
    * configuration entities that depend on them. For example, fields
    * should be created before field instances.
+   *
+   * @param string $collection
+   *   The storage collection to operate on.
    */
-  protected function addChangelistCreate() {
-    $creates = array_diff($this->sourceNames, $this->targetNames);
-    $this->addChangeList('create', $creates);
+  protected function addChangelistCreate($collection) {
+    $creates = array_diff($this->sourceNames[$collection], $this->targetNames[$collection]);
+    $this->addChangeList($collection, 'create', $creates);
   }
 
   /**
@@ -184,19 +250,22 @@ protected function addChangelistCreate() {
    * The list of updates is sorted so that dependencies are created before
    * configuration entities that depend on them. For example, fields
    * should be updated before field instances.
+   *
+   * @param string $collection
+   *   The storage collection to operate on.
    */
-  protected function addChangelistUpdate() {
+  protected function addChangelistUpdate($collection) {
     $recreates = array();
-    foreach (array_intersect($this->sourceNames, $this->targetNames) as $name) {
-      if ($this->sourceData[$name] !== $this->targetData[$name]) {
-        if (isset($this->sourceData[$name]['uuid']) && $this->sourceData[$name]['uuid'] != $this->targetData[$name]['uuid']) {
+    foreach (array_intersect($this->sourceNames[$collection], $this->targetNames[$collection]) as $name) {
+      if ($this->sourceData[$collection][$name] !== $this->targetData[$collection][$name]) {
+        if (isset($this->sourceData[$collection][$name]['uuid']) && $this->sourceData[$collection][$name]['uuid'] != $this->targetData[$collection][$name]['uuid']) {
           // The entity has the same file as an existing entity but the UUIDs do
           // not match. This means that the entity has been recreated so config
           // synchronisation should do the same.
           $recreates[] = $name;
         }
         else {
-          $this->addChangeList('update', array($name));
+          $this->addChangeList($collection, 'update', array($name));
         }
       }
     }
@@ -204,8 +273,8 @@ protected function addChangelistUpdate() {
     if (!empty($recreates)) {
       // Recreates should become deletes and creates. Deletes should be ordered
       // so that dependencies are deleted first.
-      $this->addChangeList('create', $recreates, $this->sourceNames);
-      $this->addChangeList('delete', $recreates, array_reverse($this->targetNames));
+      $this->addChangeList($collection, 'create', $recreates, $this->sourceNames[$collection]);
+      $this->addChangeList($collection, 'delete', $recreates, array_reverse($this->targetNames[$collection]));
 
     }
   }
@@ -216,17 +285,20 @@ protected function addChangelistUpdate() {
    * The list of renames is created from the different source and target names
    * with same UUID. These changes will be removed from the create and delete
    * lists.
+   *
+   * @param string $collection
+   *   The storage collection to operate on.
    */
-  protected function addChangelistRename() {
+  protected function addChangelistRename($collection) {
     // Renames will be present in both the create and delete lists.
-    $create_list = $this->getChangelist('create');
-    $delete_list = $this->getChangelist('delete');
+    $create_list = $this->getChangelist('create', $collection);
+    $delete_list = $this->getChangelist('delete', $collection);
     if (empty($create_list) || empty($delete_list)) {
       return;
     }
 
     $create_uuids = array();
-    foreach ($this->sourceData as $id => $data) {
+    foreach ($this->sourceData[$collection] as $id => $data) {
       if (isset($data['uuid']) && in_array($id, $create_list)) {
         $create_uuids[$data['uuid']] = $id;
       }
@@ -245,50 +317,52 @@ protected function addChangelistRename() {
     // Node type is a good example of a configuration entity that renames other
     // configuration when it is renamed.
     // @see \Drupal\node\Entity\NodeType::postSave()
-    foreach ($this->targetNames as $name) {
-      $data = $this->targetData[$name];
+    foreach ($this->targetNames[$collection] as $name) {
+      $data = $this->targetData[$collection][$name];
       if (isset($data['uuid']) && isset($create_uuids[$data['uuid']])) {
         // Remove the item from the create list.
-        $this->removeFromChangelist('create', $create_uuids[$data['uuid']]);
+        $this->removeFromChangelist($collection, 'create', $create_uuids[$data['uuid']]);
         // Remove the item from the delete list.
-        $this->removeFromChangelist('delete', $name);
+        $this->removeFromChangelist($collection, 'delete', $name);
         // Create the rename name.
         $renames[] = $this->createRenameName($name, $create_uuids[$data['uuid']]);
       }
     }
 
-    $this->addChangeList('rename', $renames);
+    $this->addChangeList($collection, 'rename', $renames);
   }
 
   /**
    * Removes the entry from the given operation changelist for the given name.
    *
+   * @param string $collection
+   *   The storage collection to operate on.
    * @param string $op
    *   The changelist to act on. Either delete, create, rename or update.
    * @param string $name
    *   The name of the configuration to remove.
    */
-  protected function removeFromChangelist($op, $name) {
-    $key = array_search($name, $this->changelist[$op]);
+  protected function removeFromChangelist($collection, $op, $name) {
+    $key = array_search($name, $this->changelist[$collection][$op]);
     if ($key !== FALSE) {
-      unset($this->changelist[$op][$key]);
+      unset($this->changelist[$collection][$op][$key]);
     }
   }
 
   /**
    * {@inheritdoc}
    */
-  public function moveRenameToUpdate($rename) {
+  public function moveRenameToUpdate($rename, $collection = StorageInterface::DEFAULT_COLLECTION) {
     $names = $this->extractRenameNames($rename);
-    $this->removeFromChangelist('rename', $rename);
-    $this->addChangeList('update', array($names['new_name']), $this->sourceNames);
+    $this->removeFromChangelist($collection, 'rename', $rename);
+    $this->addChangeList($collection, 'update', array($names['new_name']), $this->sourceNames[$collection]);
   }
 
   /**
    * {@inheritdoc}
    */
   public function reset() {
-    $this->changelist = $this->getEmptyChangelist();
+    $this->changelist = array(StorageInterface::DEFAULT_COLLECTION => $this->getEmptyChangelist());
     $this->sourceNames = $this->targetNames = array();
     return $this->createChangelist();
   }
@@ -296,10 +370,12 @@ public function reset() {
   /**
    * {@inheritdoc}
    */
-  public function hasChanges($ops = array('delete', 'create', 'update', 'rename')) {
-    foreach ($ops as $op) {
-      if (!empty($this->changelist[$op])) {
-        return TRUE;
+  public function hasChanges() {
+    foreach ($this->getAllCollectionNames() as $collection) {
+      foreach (array('delete', 'create', 'update', 'rename') as $op) {
+        if (!empty($this->changelist[$collection][$op])) {
+          return TRUE;
+        }
       }
     }
     return FALSE;
@@ -317,12 +393,24 @@ public function validateSiteUuid() {
   /**
    * Gets and sorts configuration data from the source and target storages.
    */
-  protected function getAndSortConfigData() {
-    $this->targetData = $this->targetStorage->readMultiple($this->targetStorage->listAll());
-    $this->sourceData = $this->sourceStorage->readMultiple($this->sourceStorage->listAll());
-    $dependency_manager = new ConfigDependencyManager();
-    $this->targetNames = $dependency_manager->setData($this->targetData)->sortAll();
-    $this->sourceNames = $dependency_manager->setData($this->sourceData)->sortAll();
+  protected function getAndSortConfigData($collection) {
+    $source_storage = $this->getSourceStorage($collection);
+    $target_storage = $this->getTargetStorage($collection);
+    $target_names = $target_storage->listAll();
+    $source_names = $source_storage->listAll();
+    $this->targetData[$collection] = $target_storage->readMultiple($target_names);
+    $this->sourceData[$collection] = $source_storage->readMultiple($source_names);
+    // If the collection only supports simple configuration do not use
+    // configuration dependencies.
+    if ($this->configManager->supportsConfigurationEntities($collection)) {
+      $dependency_manager = new ConfigDependencyManager();
+      $this->targetNames[$collection] = $dependency_manager->setData($this->targetData[$collection])->sortAll();
+      $this->sourceNames[$collection] = $dependency_manager->setData($this->sourceData[$collection])->sortAll();
+    }
+    else {
+      $this->targetNames[$collection] = $target_names;
+      $this->sourceNames[$collection] = $source_names;
+    }
   }
 
   /**
@@ -352,4 +440,16 @@ public function extractRenameNames($name) {
       'new_name' => $names[1],
     );
   }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getAllCollectionNames($include_default = TRUE) {
+    $collections = array_unique(array_merge($this->sourceStorage->getAllCollectionNames(), $this->targetStorage->getAllCollectionNames()));
+    if ($include_default) {
+      array_unshift($collections, StorageInterface::DEFAULT_COLLECTION);
+    }
+    return $collections;
+  }
+
 }
diff --git a/core/lib/Drupal/Core/Config/StorageComparerInterface.php b/core/lib/Drupal/Core/Config/StorageComparerInterface.php
index f85a8aa..180f29a 100644
--- a/core/lib/Drupal/Core/Config/StorageComparerInterface.php
+++ b/core/lib/Drupal/Core/Config/StorageComparerInterface.php
@@ -15,18 +15,26 @@
   /**
    * Gets the configuration source storage.
    *
+   * @param string $collection
+   *   (optional) The storage collection to use. Defaults to the
+   *   default collection.
+   *
    * @return \Drupal\Core\Config\StorageInterface
    *   Storage object used to read configuration.
    */
-  public function getSourceStorage();
+  public function getSourceStorage($collection = StorageInterface::DEFAULT_COLLECTION);
 
   /**
    * Gets the configuration target storage.
    *
+   * @param string $collection
+   *   (optional) The storage collection to use. Defaults to the
+   *   default collection.
+   *
    * @return \Drupal\Core\Config\StorageInterface
    *   Storage object used to write configuration.
    */
-  public function getTargetStorage();
+  public function getTargetStorage($collection = StorageInterface::DEFAULT_COLLECTION);
 
   /**
    * Gets an empty changelist.
@@ -42,11 +50,14 @@ public function getEmptyChangelist();
    * @param string $op
    *   (optional) A change operation. Either delete, create or update. If
    *   supplied the returned list will be limited to this operation.
+   * @param string $collection
+   *   (optional) The collection to get the changelist for. Defaults to the
+   *   default collection.
    *
    * @return array
    *   An array of config changes that are yet to be imported.
    */
-  public function getChangelist($op = NULL);
+  public function getChangelist($op = NULL, $collection = StorageInterface::DEFAULT_COLLECTION);
 
   /**
    * Recalculates the differences.
@@ -63,14 +74,10 @@ public function reset();
    *
    * @see \Drupal\Core\Config\StorageComparerInterface::createChangelist().
    *
-   * @param array $ops
-   *   The operations to check for changes. Defaults to all operations, i.e.
-   *   array('delete', 'create', 'update').
-   *
    * @return bool
    *   TRUE if there are changes to process and FALSE if not.
    */
-  public function hasChanges($ops = array('delete', 'create', 'update'));
+  public function hasChanges();
 
   /**
    * Validates that the system.site::uuid in the source and target match.
@@ -85,10 +92,13 @@ public function validateSiteUuid();
    *
    * @param string $rename
    *   The rename name, as provided by ConfigImporter::createRenameName().
+   * @param string $collection
+   *   (optional) The collection where the configuration is stored. Defaults to
+   *   the default collection.
    *
    * @see \Drupal\Core\Config\ConfigImporter::createRenameName()
    */
-  public function moveRenameToUpdate($rename);
+  public function moveRenameToUpdate($rename, $collection = StorageInterface::DEFAULT_COLLECTION);
 
   /**
    * Extracts old and new configuration names from a configuration change name.
@@ -106,4 +116,15 @@ public function moveRenameToUpdate($rename);
    */
   public function extractRenameNames($name);
 
+  /**
+   * Gets the existing collections from both the target and source storage.
+   *
+   * @param bool $include_default
+   *   (optional) Include the default collection. Defaults to TRUE.
+   *
+   * @return array
+   *   An array of existing collection names.
+   */
+  public function getAllCollectionNames($include_default = TRUE);
+
 }
diff --git a/core/lib/Drupal/Core/Config/StorageInterface.php b/core/lib/Drupal/Core/Config/StorageInterface.php
index 8b99784..94a6a9f 100644
--- a/core/lib/Drupal/Core/Config/StorageInterface.php
+++ b/core/lib/Drupal/Core/Config/StorageInterface.php
@@ -16,6 +16,11 @@
 interface StorageInterface {
 
   /**
+   * The default collection name.
+   */
+  const DEFAULT_COLLECTION = '';
+
+  /**
    * Returns whether a configuration object exists.
    *
    * @param string $name
@@ -156,4 +161,52 @@ public function listAll($prefix = '');
    */
   public function deleteAll($prefix = '');
 
+  /**
+   * Creates a collection on the storage.
+   *
+   * A configuration storage can contain multiple sets of configuration objects
+   * in partitioned collections. The collection name identifies the current
+   * collection used.
+   *
+   * Implementations of this method must provide a new instance to avoid side
+   * effects caused by the fact that Config objects have their storage injected.
+   *
+   * @param string $collection
+   *   The collection name. Valid collection names conform to the following
+   *   regex [a-zA-Z_.]. A storage does not need to have a collection set.
+   *   However, if a collection is set, then storage should use it to store
+   *   configuration in a way that allows retrieval of configuration for a
+   *   particular collection. Collections can be nested, for example
+   *   'language.de'. If this is a file system then we could create a language
+   *   folder with a subfolder named de. If this is a database table then there
+   *   could be a collection column which will store the value 'language.de'.
+   *   Storage nested levels should be consistent. If a collection with the name
+   *   'language.de' exists then a collections with the names 'language' or
+   *   'language.en.gb' should not be used.
+   *
+   * @return \Drupal\Core\Config\StorageInterface
+   *   A new instance of the storage backend with the collection set.
+   */
+  public function createCollection($collection);
+
+  /**
+   * Gets the existing collections.
+   *
+   * A configuration storage can contain multiple sets of configuration objects
+   * in partitioned collections. The collection key name identifies the current
+   * collection used.
+   *
+   * @return array
+   *   An array of existing collection names.
+   */
+  public function getAllCollectionNames();
+
+  /**
+   * Gets the name of the current collection the storage is using.
+   *
+   * @return string
+   *   The current collection name.
+   */
+  public function getCollectionName();
+
 }
diff --git a/core/modules/config/config.routing.yml b/core/modules/config/config.routing.yml
index f2a944a..0fdb30b 100644
--- a/core/modules/config/config.routing.yml
+++ b/core/modules/config/config.routing.yml
@@ -14,6 +14,14 @@ config.diff:
   requirements:
     _permission: 'synchronize configuration'
 
+config.diff_collection:
+  path: '/admin/config/development/configuration/sync/diff_collection/{collection}/{source_name}/{target_name}'
+  defaults:
+    _content: '\Drupal\config\Controller\ConfigController::diff'
+    target_name: NULL
+  requirements:
+    _permission: 'synchronize configuration'
+
 config.export_download:
   path: '/admin/config/development/configuration/full/export-download'
   defaults:
diff --git a/core/modules/config/lib/Drupal/config/Controller/ConfigController.php b/core/modules/config/lib/Drupal/config/Controller/ConfigController.php
index 88cdeab..ff91637 100644
--- a/core/modules/config/lib/Drupal/config/Controller/ConfigController.php
+++ b/core/modules/config/lib/Drupal/config/Controller/ConfigController.php
@@ -85,9 +85,15 @@ public function downloadExport() {
     file_unmanaged_delete(file_directory_temp() . '/config.tar.gz');
 
     $archiver = new ArchiveTar(file_directory_temp() . '/config.tar.gz', 'gz');
-    foreach (\Drupal::service('config.storage')->listAll() as $name) {
+    foreach ($this->targetStorage->listAll() as $name) {
       $archiver->addString("$name.yml", Yaml::encode(\Drupal::config($name)->get()));
     }
+    foreach ($this->targetStorage->getAllCollectionNames() as $collection) {
+      $collection_storage = $this->targetStorage->createCollection($collection);
+      foreach ($collection_storage->listAll() as $name) {
+        $archiver->addString(str_replace('.', '/', $collection) . "/$name.yml", Yaml::encode($collection_storage->read($name)));
+      }
+    }
 
     $request = new Request(array('file' => 'config.tar.gz'));
     return $this->fileDownloadController->download($request, 'temporary');
@@ -96,15 +102,23 @@ public function downloadExport() {
   /**
    * Shows diff of specificed configuration file.
    *
-   * @param string $config_file
+   * @param string $source_name
    *   The name of the configuration file.
+   * @param string $target_name
+   *   (optional) The name of the target configuration file if different from
+   *   the $source_name.
+   * @param string $collection
+   *   (optional) The configuration collection name. Defaults to the default
+   *   collection.
    *
    * @return string
    *   Table showing a two-way diff between the active and staged configuration.
    */
-  public function diff($source_name, $target_name = NULL) {
-
-    $diff = $this->configManager->diff($this->targetStorage, $this->sourceStorage, $source_name, $target_name);
+  public function diff($source_name, $target_name = NULL, $collection = NULL) {
+    if (!isset($collection)) {
+      $collection = StorageInterface::DEFAULT_COLLECTION;
+    }
+    $diff = $this->configManager->diff($this->targetStorage, $this->sourceStorage, $source_name, $target_name, $collection);
     $formatter = new \DrupalDiffFormatter();
     $formatter->show_header = FALSE;
 
diff --git a/core/modules/config/lib/Drupal/config/Form/ConfigSync.php b/core/modules/config/lib/Drupal/config/Form/ConfigSync.php
index a9eaac7..9786fb9 100644
--- a/core/modules/config/lib/Drupal/config/Form/ConfigSync.php
+++ b/core/modules/config/lib/Drupal/config/Form/ConfigSync.php
@@ -160,7 +160,7 @@ public function buildForm(array $form, array &$form_state) {
     );
 
     $source_list = $this->sourceStorage->listAll();
-    $storage_comparer = new StorageComparer($this->sourceStorage, $this->targetStorage);
+    $storage_comparer = new StorageComparer($this->sourceStorage, $this->targetStorage, $this->configManager);
     if (empty($source_list) || !$storage_comparer->createChangelist()->hasChanges()) {
       $form['no_changes'] = array(
         '#type' => 'table',
@@ -184,71 +184,86 @@ public function buildForm(array $form, array &$form_state) {
     // Add the AJAX library to the form for dialog support.
     $form['#attached']['library'][] = 'core/drupal.ajax';
 
-    foreach ($storage_comparer->getChangelist() as $config_change_type => $config_names) {
-      if (empty($config_names)) {
-        continue;
-      }
-
-      // @todo A table caption would be more appropriate, but does not have the
-      //   visual importance of a heading.
-      $form[$config_change_type]['heading'] = array(
-        '#type' => 'html_tag',
-        '#tag' => 'h3',
-      );
-      switch ($config_change_type) {
-        case 'create':
-          $form[$config_change_type]['heading']['#value'] = format_plural(count($config_names), '@count new', '@count new');
-          break;
-
-        case 'update':
-          $form[$config_change_type]['heading']['#value'] = format_plural(count($config_names), '@count changed', '@count changed');
-          break;
-
-        case 'delete':
-          $form[$config_change_type]['heading']['#value'] = format_plural(count($config_names), '@count removed', '@count removed');
-          break;
-
-        case 'rename':
-          $form[$config_change_type]['heading']['#value'] = format_plural(count($config_names), '@count renamed', '@count renamed');
-          break;
+    foreach ($storage_comparer->getAllCollectionNames() as $collection) {
+      if ($collection != StorageInterface::DEFAULT_COLLECTION) {
+        $form[$collection]['collection_heading'] = array(
+          '#type' => 'html_tag',
+          '#tag' => 'h2',
+          '#value' => $this->t('!collection configuration collection', array('!collection' => $collection)),
+        );
       }
-      $form[$config_change_type]['list'] = array(
-        '#type' => 'table',
-        '#header' => array('Name', 'Operations'),
-      );
-
-      foreach ($config_names as $config_name) {
-        if ($config_change_type == 'rename') {
-          $names = $storage_comparer->extractRenameNames($config_name);
-          $href = $this->urlGenerator->getPathFromRoute('config.diff', array('source_name' => $names['old_name'], 'target_name' => $names['new_name']));
-          $config_name = $this->t('!source_name to !target_name', array('!source_name' => $names['old_name'], '!target_name' => $names['new_name']));
+      foreach ($storage_comparer->getChangelist(NULL, $collection) as $config_change_type => $config_names) {
+        if (empty($config_names)) {
+          continue;
         }
-        else {
-          $href = $this->urlGenerator->getPathFromRoute('config.diff', array('source_name' => $config_name));
+
+        // @todo A table caption would be more appropriate, but does not have the
+        //   visual importance of a heading.
+        $form[$collection][$config_change_type]['heading'] = array(
+          '#type' => 'html_tag',
+          '#tag' => 'h3',
+        );
+        switch ($config_change_type) {
+          case 'create':
+            $form[$collection][$config_change_type]['heading']['#value'] = format_plural(count($config_names), '@count new', '@count new');
+            break;
+
+          case 'update':
+            $form[$collection][$config_change_type]['heading']['#value'] = format_plural(count($config_names), '@count changed', '@count changed');
+            break;
+
+          case 'delete':
+            $form[$collection][$config_change_type]['heading']['#value'] = format_plural(count($config_names), '@count removed', '@count removed');
+            break;
+
+          case 'rename':
+            $form[$collection][$config_change_type]['heading']['#value'] = format_plural(count($config_names), '@count renamed', '@count renamed');
+            break;
         }
-        $links['view_diff'] = array(
-          'title' => $this->t('View differences'),
-          'href' => $href,
-          'attributes' => array(
-            'class' => array('use-ajax'),
-            'data-accepts' => 'application/vnd.drupal-modal',
-            'data-dialog-options' => json_encode(array(
-              'width' => 700
-            )),
-          ),
+        $form[$collection][$config_change_type]['list'] = array(
+          '#type' => 'table',
+          '#header' => array('Name', 'Operations'),
         );
-        $form[$config_change_type]['list']['#rows'][] = array(
-          'name' => $config_name,
-          'operations' => array(
-            'data' => array(
-              '#type' => 'operations',
-              '#links' => $links,
+
+        foreach ($config_names as $config_name) {
+          if ($config_change_type == 'rename') {
+            $names = $storage_comparer->extractRenameNames($config_name);
+            $route_options = array('source_name' => $names['old_name'], 'target_name' => $names['new_name']);
+            $config_name = $this->t('!source_name to !target_name', array('!source_name' => $names['old_name'], '!target_name' => $names['new_name']));
+          }
+          else {
+            $route_options = array('source_name' => $config_name);
+          }
+          if ($collection != StorageInterface::DEFAULT_COLLECTION) {
+            $route_options['collection'] = $collection;
+            $href = $this->urlGenerator->getPathFromRoute('config.diff_collection', $route_options);
+          }
+          else {
+            $href = $this->urlGenerator->getPathFromRoute('config.diff', $route_options);
+          }
+          $links['view_diff'] = array(
+            'title' => $this->t('View differences'),
+            'href' => $href,
+            'attributes' => array(
+              'class' => array('use-ajax'),
+              'data-accepts' => 'application/vnd.drupal-modal',
+              'data-dialog-options' => json_encode(array(
+                'width' => 700
+              )),
             ),
-          ),
-        );
+          );
+          $form[$collection][$config_change_type]['list']['#rows'][] = array(
+            'name' => $config_name,
+            'operations' => array(
+              'data' => array(
+                '#type' => 'operations',
+                '#links' => $links,
+              ),
+            ),
+          );
+        }
       }
     }
-
     return $form;
   }
 
diff --git a/core/modules/config/lib/Drupal/config/Tests/ConfigDiffTest.php b/core/modules/config/lib/Drupal/config/Tests/ConfigDiffTest.php
index 6f3b3de..138b861 100644
--- a/core/modules/config/lib/Drupal/config/Tests/ConfigDiffTest.php
+++ b/core/modules/config/lib/Drupal/config/Tests/ConfigDiffTest.php
@@ -113,4 +113,36 @@ function testDiff() {
     $this->assertEqual(count($diff->edits), 2, 'There are two items in the diff.');
   }
 
+  /**
+   * Tests calculating the difference between two sets of config collections.
+   */
+  function testCollectionDiff() {
+    /** @var \Drupal\Core\Config\StorageInterface $active */
+    $active = $this->container->get('config.storage');
+    /** @var \Drupal\Core\Config\StorageInterface $staging */
+    $staging = $this->container->get('config.storage.staging');
+    $active_test_collection = $active->createCollection('test');
+    $staging_test_collection = $staging->createCollection('test');
+
+    $config_name = 'config_test.test';
+    $data = array('foo' => 'bar');
+
+    $active->write($config_name, $data);
+    $staging->write($config_name, $data);
+    $active_test_collection->write($config_name, $data);
+    $staging_test_collection->write($config_name, array('foo' => 'baz'));
+
+    // Test the fields match in the default collection diff.
+    $diff = \Drupal::service('config.manager')->diff($active, $staging, $config_name);
+    $this->assertEqual($diff->edits[0]->type, 'copy',  'The first item in the diff is a copy.');
+    $this->assertEqual(count($diff->edits), 1, 'There is one item in the diff');
+
+    // Test that the differences are detected when diffing the collection.
+    $diff = \Drupal::service('config.manager')->diff($active, $staging, $config_name, NULL, 'test');
+    $this->assertEqual($diff->edits[0]->type, 'change',  'The second item in the diff is a copy.');
+    $this->assertEqual($diff->edits[0]->orig, array('foo: bar'));
+    $this->assertEqual($diff->edits[0]->closing, array('foo: baz'));
+    $this->assertEqual($diff->edits[1]->type, 'copy',  'The second item in the diff is a copy.');
+  }
+
 }
diff --git a/core/modules/config/lib/Drupal/config/Tests/ConfigExportImportUITest.php b/core/modules/config/lib/Drupal/config/Tests/ConfigExportImportUITest.php
index 0a01bd1..b087124 100644
--- a/core/modules/config/lib/Drupal/config/Tests/ConfigExportImportUITest.php
+++ b/core/modules/config/lib/Drupal/config/Tests/ConfigExportImportUITest.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\config\Tests;
 
+use Drupal\Core\Archiver\ArchiveTar;
 use Drupal\simpletest\WebTestBase;
 
 /**
@@ -130,4 +131,117 @@ public function testExportImport() {
     $this->drupalGet('node/add');
     $this->assertFieldByName("{$this->field->name}[0][value]", '', 'Widget is displayed');
   }
+
+  /**
+   * Tests an export and import of collections.
+   */
+  public function testExportImportCollections() {
+
+    /** @var \Drupal\Core\Config\StorageInterface $active_storage */
+    $active_storage = \Drupal::service('config.storage');
+    $test1_storage = $active_storage->createCollection('collection.test1');
+    $test1_storage->write('config_test.create', array('foo' => 'bar'));
+    $test1_storage->write('config_test.update', array('foo' => 'bar'));
+    $test2_storage = $active_storage->createCollection('collection.test2');
+    $test2_storage->write('config_test.another_create', array('foo' => 'bar'));
+    $test2_storage->write('config_test.another_update', array('foo' => 'bar'));
+
+    // Export the configuration.
+    $this->drupalPostForm('admin/config/development/configuration/full/export', array(), 'Export');
+    $this->tarball = $this->drupalGetContent();
+    $filename = file_directory_temp() .'/' . $this->randomName();
+    file_put_contents($filename, $this->tarball);
+
+    // Set up the active storage collections to test import.
+    $test1_storage->delete('config_test.create');
+    $test1_storage->write('config_test.update', array('foo' => 'baz'));
+    $test1_storage->write('config_test.delete', array('foo' => 'bar'));
+    $test2_storage->delete('config_test.another_create');
+    $test2_storage->write('config_test.another_update', array('foo' => 'baz'));
+    $test2_storage->write('config_test.another_delete', array('foo' => 'bar'));
+
+    // Create a snapshot.
+    $snapshot_storage = \Drupal::service('config.storage.snapshot');
+    \Drupal::service('config.manager')->createSnapshot($active_storage, $snapshot_storage);
+
+    // Ensure that the snapshot has the expected collection data before import.
+    $test1_snapshot = $snapshot_storage->createCollection('collection.test1');
+    $data = $test1_snapshot->read('config_test.delete');
+    $this->assertEqual($data, array('foo' => 'bar'), 'The config_test.delete in collection.test1 exists in the snapshot storage.');
+    $data = $test1_snapshot->read('config_test.update');
+    $this->assertEqual($data, array('foo' => 'baz'), 'The config_test.update in collection.test1 exists in the snapshot storage.');
+    $this->assertFalse($test1_snapshot->read('config_test.create'), 'The config_test.create in collection.test1 does not exist in the snapshot storage.');
+    $test2_snapshot = $snapshot_storage->createCollection('collection.test2');
+    $data = $test2_snapshot->read('config_test.another_delete');
+    $this->assertEqual($data, array('foo' => 'bar'), 'The config_test.another_delete in collection.test2 exists in the snapshot storage.');
+    $data = $test2_snapshot->read('config_test.another_update');
+    $this->assertEqual($data, array('foo' => 'baz'), 'The config_test.another_update in collection.test2 exists in the snapshot storage.');
+    $this->assertFalse($test2_snapshot->read('config_test.another_create'), 'The config_test.another_create in collection.test2 does not exist in the snapshot storage.');
+
+    // Create the tar contains the expected contect for the collections.
+    $tar = new ArchiveTar($filename, 'gz');
+    $content_list = $tar->listContent();
+    // Convert the list of files into something easy to search.
+    $files = array();
+    foreach ($content_list as $file) {
+      $files[] = $file['filename'];
+    }
+    $this->assertTrue(in_array('collection/test1/config_test.create.yml', $files), 'Config export contains collection/test1/config_test.create.yml.');
+    $this->assertTrue(in_array('collection/test2/config_test.another_create.yml', $files), 'Config export contains collection/test2/config_test.another_create.yml.');
+    $this->assertTrue(in_array('collection/test1/config_test.update.yml', $files), 'Config export contains collection/test1/config_test.update.yml.');
+    $this->assertTrue(in_array('collection/test2/config_test.another_update.yml', $files), 'Config export contains collection/test2/config_test.another_update.yml.');
+    $this->assertFalse(in_array('collection/test1/config_test.delete.yml', $files), 'Config export does not contain collection/test1/config_test.delete.yml.');
+    $this->assertFalse(in_array('collection/test2/config_test.another_delete.yml', $files), 'Config export does not contain collection/test2/config_test.another_delete.yml.');
+
+    $this->drupalPostForm('admin/config/development/configuration/full/import', array('files[import_tarball]' => $filename), 'Upload');
+    // Verify that there are configuration differences to import.
+    $this->drupalGet('admin/config/development/configuration');
+    $this->assertNoText(t('There are no configuration changes.'));
+    $this->assertText(t('!collection configuration collection', array('!collection' => 'collection.test1')));
+    $this->assertText(t('!collection configuration collection', array('!collection' => 'collection.test2')));
+    $this->assertText('config_test.create');
+    $this->assertLinkByHref('admin/config/development/configuration/sync/diff_collection/collection.test1/config_test.create');
+    $this->assertText('config_test.update');
+    $this->assertLinkByHref('admin/config/development/configuration/sync/diff_collection/collection.test1/config_test.update');
+    $this->assertText('config_test.delete');
+    $this->assertLinkByHref('admin/config/development/configuration/sync/diff_collection/collection.test1/config_test.delete');
+    $this->assertText('config_test.another_create');
+    $this->assertLinkByHref('admin/config/development/configuration/sync/diff_collection/collection.test2/config_test.another_create');
+    $this->assertText('config_test.another_update');
+    $this->assertLinkByHref('admin/config/development/configuration/sync/diff_collection/collection.test2/config_test.another_update');
+    $this->assertText('config_test.another_delete');
+    $this->assertLinkByHref('admin/config/development/configuration/sync/diff_collection/collection.test2/config_test.another_delete');
+
+    $this->drupalPostForm(NULL, array(), 'Import all');
+    $this->assertText(t('There are no configuration changes.'));
+
+    // Test data in collections.
+    $data = $test1_storage->read('config_test.create');
+    $this->assertEqual($data, array('foo' => 'bar'), 'The config_test.create in collection.test1 has been created.');
+    $data = $test1_storage->read('config_test.update');
+    $this->assertEqual($data, array('foo' => 'bar'), 'The config_test.update in collection.test1 has been updated.');
+    $this->assertFalse($test1_storage->read('config_test.delete'), 'The config_test.delete in collection.test1 has been deleted.');
+
+    $data = $test2_storage->read('config_test.another_create');
+    $this->assertEqual($data, array('foo' => 'bar'), 'The config_test.another_create in collection.test2 has been created.');
+    $data = $test2_storage->read('config_test.another_update');
+    $this->assertEqual($data, array('foo' => 'bar'), 'The config_test.another_update in collection.test2 has been updated.');
+    $this->assertFalse($test2_storage->read('config_test.another_delete'), 'The config_test.another_delete in collection.test2 has been deleted.');
+
+    // Ensure that the snapshot has been updated with the collection data.
+    $snapshot_storage = \Drupal::service('config.storage.snapshot');
+    $test1_snapshot = $snapshot_storage->createCollection('collection.test1');
+    $data = $test1_snapshot->read('config_test.create');
+    $this->assertEqual($data, array('foo' => 'bar'), 'The config_test.create in collection.test1 has been created in the snapshot storage.');
+    $data = $test1_snapshot->read('config_test.update');
+    $this->assertEqual($data, array('foo' => 'bar'), 'The config_test.update in collection.test1 has been updated in the snapshot storage.');
+    $this->assertFalse($test1_snapshot->read('config_test.delete'), 'The config_test.delete in collection.test1 does not exist in the snapshot storage.');
+    $test2_snapshot = $snapshot_storage->createCollection('collection.test2');
+    $data = $test2_snapshot->read('config_test.another_create');
+    $this->assertEqual($data, array('foo' => 'bar'), 'The config_test.another_create in collection.test2 has been created in the snapshot storage.');
+    $data = $test2_snapshot->read('config_test.another_update');
+    $this->assertEqual($data, array('foo' => 'bar'), 'The config_test.another_update in collection.test2 has been updated in the snapshot storage.');
+    $this->assertFalse($test2_snapshot->read('config_test.another_delete'), 'The config_test.another_delete in collection.test2 does not exist in the snapshot storage.');
+  }
+
 }
diff --git a/core/modules/config/lib/Drupal/config/Tests/ConfigImportAllTest.php b/core/modules/config/lib/Drupal/config/Tests/ConfigImportAllTest.php
index 6f7f67c..74a9535 100644
--- a/core/modules/config/lib/Drupal/config/Tests/ConfigImportAllTest.php
+++ b/core/modules/config/lib/Drupal/config/Tests/ConfigImportAllTest.php
@@ -111,7 +111,8 @@ public function testInstallUninstall() {
     // Ensure that we have no configuration changes to import.
     $storage_comparer = new StorageComparer(
       $this->container->get('config.storage.staging'),
-      $this->container->get('config.storage')
+      $this->container->get('config.storage'),
+      $this->container->get('config.manager')
     );
     $this->assertIdentical($storage_comparer->createChangelist()->getChangelist(), $storage_comparer->getEmptyChangelist());
   }
diff --git a/core/modules/config/lib/Drupal/config/Tests/ConfigImportRecreateTest.php b/core/modules/config/lib/Drupal/config/Tests/ConfigImportRecreateTest.php
index 21ee6c5..3ce6b12 100644
--- a/core/modules/config/lib/Drupal/config/Tests/ConfigImportRecreateTest.php
+++ b/core/modules/config/lib/Drupal/config/Tests/ConfigImportRecreateTest.php
@@ -49,7 +49,8 @@ public function setUp() {
     // Set up the ConfigImporter object for testing.
     $storage_comparer = new StorageComparer(
       $this->container->get('config.storage.staging'),
-      $this->container->get('config.storage')
+      $this->container->get('config.storage'),
+      $this->container->get('config.manager')
     );
     $this->configImporter = new ConfigImporter(
       $storage_comparer->createChangelist(),
diff --git a/core/modules/config/lib/Drupal/config/Tests/ConfigImportRenameValidationTest.php b/core/modules/config/lib/Drupal/config/Tests/ConfigImportRenameValidationTest.php
index f2ca9aa..fbffae7 100644
--- a/core/modules/config/lib/Drupal/config/Tests/ConfigImportRenameValidationTest.php
+++ b/core/modules/config/lib/Drupal/config/Tests/ConfigImportRenameValidationTest.php
@@ -56,7 +56,8 @@ public function setUp() {
     // Set up the ConfigImporter object for testing.
     $storage_comparer = new StorageComparer(
       $this->container->get('config.storage.staging'),
-      $this->container->get('config.storage')
+      $this->container->get('config.storage'),
+      $this->container->get('config.manager')
     );
     $this->configImporter = new ConfigImporter(
       $storage_comparer->createChangelist(),
diff --git a/core/modules/config/lib/Drupal/config/Tests/ConfigImporterTest.php b/core/modules/config/lib/Drupal/config/Tests/ConfigImporterTest.php
index b3c1633..21ce402 100644
--- a/core/modules/config/lib/Drupal/config/Tests/ConfigImporterTest.php
+++ b/core/modules/config/lib/Drupal/config/Tests/ConfigImporterTest.php
@@ -54,7 +54,8 @@ function setUp() {
     // Set up the ConfigImporter object for testing.
     $storage_comparer = new StorageComparer(
       $this->container->get('config.storage.staging'),
-      $this->container->get('config.storage')
+      $this->container->get('config.storage'),
+      $this->container->get('config.manager')
     );
     $this->configImporter = new ConfigImporter(
       $storage_comparer->createChangelist(),
diff --git a/core/modules/config/lib/Drupal/config/Tests/ConfigInstallTest.php b/core/modules/config/lib/Drupal/config/Tests/ConfigInstallTest.php
index 3e97adf..b25f92c 100644
--- a/core/modules/config/lib/Drupal/config/Tests/ConfigInstallTest.php
+++ b/core/modules/config/lib/Drupal/config/Tests/ConfigInstallTest.php
@@ -11,6 +11,8 @@
 
 /**
  * Tests installation of configuration objects in installation functionality.
+ *
+ * @see \Drupal\Core\Config\ConfigInstaller
  */
 class ConfigInstallTest extends DrupalUnitTestBase {
   public static function getInfo() {
@@ -78,6 +80,99 @@ function testModuleInstallation() {
     \Drupal::config('core.extension')->set('module', array())->save();
     \Drupal::service('config.manager')->uninstall('module', 'config_test');
     $this->assertFalse(\Drupal::service('config.typed')->hasConfigSchema('config_schema_test.schema_in_install'), 'Configuration schema for config_schema_test.schema_in_install does not exist.');
+  }
+
+  /**
+   * Tests that collections are ignored if the event does not return anything.
+   */
+  public function testCollectionInstallationNoCollections() {
+    // Install the test module.
+    $this->enableModules(array('config_collection_install_test'));
+    $this->installConfig(array('config_collection_install_test'));
+    /** @var \Drupal\Core\Config\StorageInterface $active_storage */
+    $active_storage = \Drupal::service('config.storage');
+    $this->assertEqual(array(), $active_storage->getAllCollectionNames());
+  }
+
+  /**
+   * Tests config objects in collections are installed as expected.
+   */
+  public function testCollectionInstallationCollections() {
+    $collections = array(
+      'another_collection',
+      'collection.test1',
+      'collection.test2',
+    );
+    // Set the event listener to return three possible collections.
+    // @see \Drupal\config_collection_install_test\EventSubscriber
+    \Drupal::state()->set('config_collection_install_test.collection_names', $collections);
+    // Install the test module.
+    $this->enableModules(array('config_collection_install_test'));
+    $this->installConfig(array('config_collection_install_test'));
+    /** @var \Drupal\Core\Config\StorageInterface $active_storage */
+    $active_storage = \Drupal::service('config.storage');
+    $this->assertEqual($collections, $active_storage->getAllCollectionNames());
+    foreach ($collections as $collection) {
+      $collection_storage = $active_storage->createCollection($collection);
+      $data = $collection_storage->read('config_collection_install_test.test');
+      $this->assertEqual($collection, $data['collection']);
+    }
+
+    // Test that the we can use the config installer to install all the
+    // available default configuration in a particular collection for enabled
+    // extensions.
+    \Drupal::service('config.installer')->installCollectionDefaultConfig('entity');
+    // The 'entity' collection will not exist because the 'config_test' module
+    // is not enabled.
+    $this->assertEqual($collections, $active_storage->getAllCollectionNames());
+    // Enable the 'config_test' module and try again.
+    $this->enableModules(array('config_test'));
+    \Drupal::service('config.installer')->installCollectionDefaultConfig('entity');
+    $collections[] = 'entity';
+    $this->assertEqual($collections, $active_storage->getAllCollectionNames());
+    $collection_storage = $active_storage->createCollection('entity');
+    $data = $collection_storage->read('config_test.dynamic.dotted.default');
+    $this->assertIdentical(array('label' => 'entity'), $data);
+
+    // Test that the config manager uninstalls configuration from collections
+    // as expected.
+    \Drupal::service('config.manager')->uninstall('module', 'config_collection_install_test');
+    $this->assertEqual(array('entity'), $active_storage->getAllCollectionNames());
+    \Drupal::service('config.manager')->uninstall('module', 'config_test');
+    $this->assertEqual(array(), $active_storage->getAllCollectionNames());
+  }
 
+  /**
+   * Tests collections which do not support config entities install correctly.
+   *
+   * Config entity detection during config installation is done by matching
+   * config name prefixes. If a collection provides a configuration with a
+   * matching name but does not support config entities it should be created
+   * using simple configuration.
+   */
+  public function testCollectionInstallationCollectionConfigEntity() {
+    $collections = array(
+      'entity',
+    );
+    \Drupal::state()->set('config_collection_install_test.collection_names', $collections);
+    // Install the test module.
+    $this->enableModules(array('config_test', 'config_collection_install_test'));
+    $this->installConfig(array('config_test'));
+    /** @var \Drupal\Core\Config\StorageInterface $active_storage */
+    $active_storage = \Drupal::service('config.storage');
+    $this->assertEqual($collections, $active_storage->getAllCollectionNames());
+    $collection_storage = $active_storage->createCollection('entity');
+
+    // The config_test.dynamic.dotted.default configuraton object saved in the
+    // active store should be a configuration entity complete with UUID. Because
+    // the entity collection does not support configuration entities the
+    // configuration object stored there with the same name should only contain
+    // a label.
+    $name = 'config_test.dynamic.dotted.default';
+    $data = $active_storage->read($name);
+    $this->assertTrue(isset($data['uuid']));
+    $data = $collection_storage->read($name);
+    $this->assertIdentical(array('label' => 'entity'), $data);
   }
+
 }
diff --git a/core/modules/config/lib/Drupal/config/Tests/ConfigSnapshotTest.php b/core/modules/config/lib/Drupal/config/Tests/ConfigSnapshotTest.php
index a0b3ecc..51ca8c9 100644
--- a/core/modules/config/lib/Drupal/config/Tests/ConfigSnapshotTest.php
+++ b/core/modules/config/lib/Drupal/config/Tests/ConfigSnapshotTest.php
@@ -45,12 +45,13 @@ function testSnapshot() {
     $active = $this->container->get('config.storage');
     $staging = $this->container->get('config.storage.staging');
     $snapshot = $this->container->get('config.storage.snapshot');
+    $config_manager = $this->container->get('config.manager');
     $config_name = 'config_test.system';
     $config_key = 'foo';
     $new_data = 'foobar';
 
-    $active_snapshot_comparer = new StorageComparer($active, $snapshot);
-    $staging_snapshot_comparer = new StorageComparer($staging, $snapshot);
+    $active_snapshot_comparer = new StorageComparer($active, $snapshot, $config_manager);
+    $staging_snapshot_comparer = new StorageComparer($staging, $snapshot, $config_manager);
 
     // Verify that we have an initial snapshot that matches the active
     // configuration. This has to be true as no config should be installed.
diff --git a/core/modules/config/lib/Drupal/config/Tests/DefaultConfigTest.php b/core/modules/config/lib/Drupal/config/Tests/DefaultConfigTest.php
index df1b335..e90a058 100644
--- a/core/modules/config/lib/Drupal/config/Tests/DefaultConfigTest.php
+++ b/core/modules/config/lib/Drupal/config/Tests/DefaultConfigTest.php
@@ -51,9 +51,9 @@ public function testDefaultConfig() {
     $default_config_storage = new TestInstallStorage();
 
     foreach ($default_config_storage->listAll() as $config_name) {
-      // @todo: remove once migration (https://drupal.org/node/2183957) and
-      // translation (https://drupal.org/node/2168609) schemas are in.
-      if (strpos($config_name, 'migrate.migration') === 0 || strpos($config_name, 'language.config') === 0) {
+      // @todo: remove once migration (https://drupal.org/node/2183957) schemas
+      // are in.
+      if (strpos($config_name, 'migrate.migration') === 0) {
         continue;
       }
 
diff --git a/core/modules/config/lib/Drupal/config/Tests/Storage/CachedStorageTest.php b/core/modules/config/lib/Drupal/config/Tests/Storage/CachedStorageTest.php
index cb00a1e..766d013 100644
--- a/core/modules/config/lib/Drupal/config/Tests/Storage/CachedStorageTest.php
+++ b/core/modules/config/lib/Drupal/config/Tests/Storage/CachedStorageTest.php
@@ -42,8 +42,8 @@ public static function getInfo() {
   function setUp() {
     parent::setUp();
     $this->filestorage = new FileStorage($this->configDirectories[CONFIG_ACTIVE_DIRECTORY]);
+    $this->storage = new CachedStorage($this->filestorage, \Drupal::service('cache_factory'));
     $this->cache = \Drupal::service('cache_factory')->get('config');
-    $this->storage = new CachedStorage($this->filestorage, $this->cache);
     // ::listAll() verifications require other configuration data to exist.
     $this->storage->write('system.performance', array());
   }
diff --git a/core/modules/config/lib/Drupal/config/Tests/Storage/ConfigStorageTestBase.php b/core/modules/config/lib/Drupal/config/Tests/Storage/ConfigStorageTestBase.php
index c112ccd..79d6311 100644
--- a/core/modules/config/lib/Drupal/config/Tests/Storage/ConfigStorageTestBase.php
+++ b/core/modules/config/lib/Drupal/config/Tests/Storage/ConfigStorageTestBase.php
@@ -181,6 +181,65 @@ function testDataTypes() {
     $this->assertIdentical($read_data, $data);
   }
 
+  /**
+   * Tests that the storage supports collections.
+   */
+  public function testCollection() {
+    $name = 'config_test.storage';
+    $data = array('foo' => 'bar');
+    $result = $this->storage->write($name, $data);
+    $this->assertIdentical($result, TRUE);
+    $this->assertIdentical($data, $this->storage->read($name));
+
+    // Create configuration in a new collection.
+    $new_storage = $this->storage->createCollection('collection.sub.new');
+    $this->assertFalse($new_storage->exists($name));
+    $this->assertEqual(array(), $new_storage->listAll());
+    $new_storage->write($name, $data);
+    $this->assertIdentical($result, TRUE);
+    $this->assertIdentical($data, $new_storage->read($name));
+    $this->assertEqual(array($name), $new_storage->listAll());
+    $this->assertTrue($new_storage->exists($name));
+    $new_data = array('foo' => 'baz');
+    $new_storage->write($name, $new_data);
+    $this->assertIdentical($result, TRUE);
+    $this->assertIdentical($new_data, $new_storage->read($name));
+
+    // Create configuration in another collection.
+    $another_storage = $this->storage->createCollection('collection.sub.another');
+    $this->assertFalse($another_storage->exists($name));
+    $this->assertEqual(array(), $another_storage->listAll());
+    $another_storage->write($name, $new_data);
+    $this->assertIdentical($result, TRUE);
+    $this->assertIdentical($new_data, $another_storage->read($name));
+    $this->assertEqual(array($name), $another_storage->listAll());
+    $this->assertTrue($another_storage->exists($name));
+
+    // Create configuration in yet another collection.
+    $alt_storage = $this->storage->createCollection('alternate');
+    $alt_storage->write($name, $new_data);
+    $this->assertIdentical($result, TRUE);
+    $this->assertIdentical($new_data, $alt_storage->read($name));
+
+    // Switch back to the collection-less mode and check the data still exists
+    // add has not been touched.
+    $this->assertIdentical($data, $this->storage->read($name));
+
+    // Check that the getAllCollectionNames() method works.
+    $this->assertIdentical(array('alternate', 'collection.sub.another', 'collection.sub.new'), $this->storage->getAllCollectionNames());
+
+    // Check that the collections are removed when they are empty.
+    $alt_storage->delete($name);
+    $this->assertIdentical(array('collection.sub.another', 'collection.sub.new'), $this->storage->getAllCollectionNames());
+
+    // Check that the having an empty collection-less storage does not break
+    // anything. Before deleting check that the previous delete did not affect
+    // data in another collection.
+    $this->assertIdentical($data, $this->storage->read($name));
+    $this->storage->delete($name);
+    $this->assertIdentical(array('collection.sub.another', 'collection.sub.new'), $this->storage->getAllCollectionNames());
+  }
+
   abstract protected function read($name);
 
   abstract protected function insert($name, $data);
@@ -188,4 +247,5 @@ function testDataTypes() {
   abstract protected function update($name, $data);
 
   abstract protected function delete($name);
+
 }
diff --git a/core/modules/config/tests/config_collection_install_test/config/install/another_collection/config_collection_install_test.test.yml b/core/modules/config/tests/config_collection_install_test/config/install/another_collection/config_collection_install_test.test.yml
new file mode 100644
index 0000000..8ea5dd5
--- /dev/null
+++ b/core/modules/config/tests/config_collection_install_test/config/install/another_collection/config_collection_install_test.test.yml
@@ -0,0 +1 @@
+collection: another_collection
\ No newline at end of file
diff --git a/core/modules/config/tests/config_collection_install_test/config/install/collection/test1/config_collection_install_test.test.yml b/core/modules/config/tests/config_collection_install_test/config/install/collection/test1/config_collection_install_test.test.yml
new file mode 100644
index 0000000..fbfa817
--- /dev/null
+++ b/core/modules/config/tests/config_collection_install_test/config/install/collection/test1/config_collection_install_test.test.yml
@@ -0,0 +1 @@
+collection: collection.test1
\ No newline at end of file
diff --git a/core/modules/config/tests/config_collection_install_test/config/install/collection/test2/config_collection_install_test.test.yml b/core/modules/config/tests/config_collection_install_test/config/install/collection/test2/config_collection_install_test.test.yml
new file mode 100644
index 0000000..9cb93ae
--- /dev/null
+++ b/core/modules/config/tests/config_collection_install_test/config/install/collection/test2/config_collection_install_test.test.yml
@@ -0,0 +1 @@
+collection: collection.test2
\ No newline at end of file
diff --git a/core/modules/config/tests/config_collection_install_test/config/install/entity/config_test.dynamic.dotted.default.yml b/core/modules/config/tests/config_collection_install_test/config/install/entity/config_test.dynamic.dotted.default.yml
new file mode 100644
index 0000000..f77c303
--- /dev/null
+++ b/core/modules/config/tests/config_collection_install_test/config/install/entity/config_test.dynamic.dotted.default.yml
@@ -0,0 +1 @@
+label: entity
diff --git a/core/modules/config/tests/config_collection_install_test/config_collection_install_test.info.yml b/core/modules/config/tests/config_collection_install_test/config_collection_install_test.info.yml
new file mode 100644
index 0000000..95c6799
--- /dev/null
+++ b/core/modules/config/tests/config_collection_install_test/config_collection_install_test.info.yml
@@ -0,0 +1,5 @@
+name: 'Configuration events test'
+type: module
+package: Testing
+version: VERSION
+core: 8.x
diff --git a/core/modules/config/tests/config_collection_install_test/config_collection_install_test.services.yml b/core/modules/config/tests/config_collection_install_test/config_collection_install_test.services.yml
new file mode 100644
index 0000000..3ee0d23
--- /dev/null
+++ b/core/modules/config/tests/config_collection_install_test/config_collection_install_test.services.yml
@@ -0,0 +1,6 @@
+services:
+  config_events_test.event_subscriber:
+    class: Drupal\config_collection_install_test\EventSubscriber
+    arguments: ['@state']
+    tags:
+      - { name: event_subscriber }
diff --git a/core/modules/config/tests/config_collection_install_test/lib/Drupal/config_collection_install_test/EventSubscriber.php b/core/modules/config/tests/config_collection_install_test/lib/Drupal/config_collection_install_test/EventSubscriber.php
new file mode 100644
index 0000000..bb481e0
--- /dev/null
+++ b/core/modules/config/tests/config_collection_install_test/lib/Drupal/config_collection_install_test/EventSubscriber.php
@@ -0,0 +1,52 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\config_collection_install_test\EventSubscriber.
+ */
+
+namespace Drupal\config_collection_install_test;
+
+use Drupal\Core\Config\ConfigCollectionNamesEvent;
+use Drupal\Core\Config\ConfigEvents;
+use Drupal\Core\State\StateInterface;
+use Symfony\Component\EventDispatcher\EventSubscriberInterface;
+
+class EventSubscriber implements EventSubscriberInterface {
+
+  /**
+   * The state key value store.
+   *
+   * @var \Drupal\Core\State\StateInterface
+   */
+  protected $state;
+
+  /**
+   * Constructs the Event Subscriber object.
+   *
+   * @param \Drupal\Core\State\StateInterface $state
+   *   The state key value store.
+   */
+  public function __construct(StateInterface $state) {
+    $this->state = $state;
+  }
+
+  /**
+   * Reacts to the ConfigEvents::COLLECTION_NAMES event.
+   *
+   * @param \Drupal\Core\Config\ConfigCollectionNamesEvent $event
+   *   The configuration collection names event.
+   */
+  public function addCollectionNames(ConfigCollectionNamesEvent $event) {
+    $event->addCollectionNames($this->state->get('config_collection_install_test.collection_names', array()));
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  static function getSubscribedEvents() {
+    $events[ConfigEvents::COLLECTION_NAMES][] = array('addCollectionNames');
+    return $events;
+  }
+
+}
diff --git a/core/modules/config/tests/config_test/config/install/language.config.de.config_test.system.yml b/core/modules/config/tests/config_test/config/install/language/de/config_test.system.yml
similarity index 100%
rename from core/modules/config/tests/config_test/config/install/language.config.de.config_test.system.yml
rename to core/modules/config/tests/config_test/config/install/language/de/config_test.system.yml
diff --git a/core/modules/config/tests/config_test/config/install/language.config.en.config_test.system.yml b/core/modules/config/tests/config_test/config/install/language/en/config_test.system.yml
similarity index 100%
rename from core/modules/config/tests/config_test/config/install/language.config.en.config_test.system.yml
rename to core/modules/config/tests/config_test/config/install/language/en/config_test.system.yml
diff --git a/core/modules/config/tests/config_test/config/install/language.config.fr.config_test.system.yml b/core/modules/config/tests/config_test/config/install/language/fr/config_test.system.yml
similarity index 100%
rename from core/modules/config/tests/config_test/config/install/language.config.fr.config_test.system.yml
rename to core/modules/config/tests/config_test/config/install/language/fr/config_test.system.yml
diff --git a/core/modules/config_translation/lib/Drupal/config_translation/Form/ConfigTranslationFormBase.php b/core/modules/config_translation/lib/Drupal/config_translation/Form/ConfigTranslationFormBase.php
index fb3ba88..13311d9 100644
--- a/core/modules/config_translation/lib/Drupal/config_translation/Form/ConfigTranslationFormBase.php
+++ b/core/modules/config_translation/lib/Drupal/config_translation/Form/ConfigTranslationFormBase.php
@@ -15,6 +15,7 @@
 use Drupal\Core\Form\BaseFormIdInterface;
 use Drupal\Core\Form\FormBase;
 use Drupal\Core\Language\Language;
+use Drupal\language\Config\LanguageConfigOverride;
 use Drupal\language\ConfigurableLanguageManagerInterface;
 use Drupal\locale\StringStorageInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
@@ -352,7 +353,7 @@ protected function buildConfigForm(Element $schema, $config_data, $base_config_d
    *   Set the configuration in this language.
    * @param \Drupal\Core\Config\Config $base_config
    *   Base configuration values, in the source language.
-   * @param \Drupal\Core\Config\Config $config_translation
+   * @param \Drupal\language\Config\LanguageConfigOverride $config_translation
    *   Translation configuration override data.
    * @param array $config_values
    *   A simple one dimensional or recursive array:
@@ -372,7 +373,7 @@ protected function buildConfigForm(Element $schema, $config_data, $base_config_d
    * @return array
    *   Translation configuration override data.
    */
-  protected function setConfig(Language $language, Config $base_config, Config $config_translation, array $config_values, $shipped_config = FALSE) {
+  protected function setConfig(Language $language, Config $base_config, LanguageConfigOverride $config_translation, array $config_values, $shipped_config = FALSE) {
     foreach ($config_values as $key => $value) {
       if (is_array($value) && !isset($value['translation'])) {
         // Traverse into this level in the configuration.
diff --git a/core/modules/language/language.module b/core/modules/language/language.module
index f35da4d..6a71fc7 100644
--- a/core/modules/language/language.module
+++ b/core/modules/language/language.module
@@ -441,6 +441,8 @@ function language_save($language) {
   $language_entity->save();
   $t_args = array('%language' => $language->name, '%langcode' => $language->id);
   if ($language->is_new) {
+    // Install any available language configuration overrides for the language.
+    \Drupal::service('language.config_factory_override')->installLanguageOverrides($language->getId());
     watchdog('language', 'The %language (%langcode) language has been created.', $t_args);
   }
   else {
diff --git a/core/modules/language/language.services.yml b/core/modules/language/language.services.yml
index 7396d57..e183e6d 100644
--- a/core/modules/language/language.services.yml
+++ b/core/modules/language/language.services.yml
@@ -16,3 +16,4 @@ services:
     arguments: ['@config.storage', '@event_dispatcher', '@config.typed']
     tags:
       - { name: config.factory.override, priority: -254 }
+      - { name: event_subscriber }
diff --git a/core/modules/language/lib/Drupal/language/Config/LanguageConfigFactoryOverride.php b/core/modules/language/lib/Drupal/language/Config/LanguageConfigFactoryOverride.php
index bfadec0..979a040 100644
--- a/core/modules/language/lib/Drupal/language/Config/LanguageConfigFactoryOverride.php
+++ b/core/modules/language/lib/Drupal/language/Config/LanguageConfigFactoryOverride.php
@@ -7,24 +7,36 @@
 
 namespace Drupal\language\Config;
 
-use Drupal\Core\Config\Config;
+use Drupal\Core\Config\ConfigCollectionNamesEvent;
+use Drupal\Core\Config\ConfigEvents;
 use Drupal\Core\Config\StorageInterface;
 use Drupal\Core\Config\TypedConfigManagerInterface;
 use Drupal\Core\Language\Language;
 use Drupal\Core\Language\LanguageDefault;
 use Symfony\Component\EventDispatcher\EventDispatcherInterface;
+use Symfony\Component\EventDispatcher\EventSubscriberInterface;
 
 /**
  * Provides language overrides for the configuration factory.
  */
-class LanguageConfigFactoryOverride implements LanguageConfigFactoryOverrideInterface {
+class LanguageConfigFactoryOverride implements LanguageConfigFactoryOverrideInterface, EventSubscriberInterface {
 
   /**
    * The configuration storage.
    *
+   * Do not access this directly. Should be accessed through self::getStorage()
+   * so that the cache of storages per langcode is used.
+   *
    * @var \Drupal\Core\Config\StorageInterface
    */
-  protected $storage;
+  protected $baseStorage;
+
+  /**
+   * An array of configuration storages keyed by langcode.
+   *
+   * @var \Drupal\Core\Config\StorageInterface[]
+   */
+  protected $storages;
 
   /**
    * The typed config manager.
@@ -58,7 +70,7 @@ class LanguageConfigFactoryOverride implements LanguageConfigFactoryOverrideInte
    *   The typed configuration manager.
    */
   public function __construct(StorageInterface $storage, EventDispatcherInterface $event_dispatcher, TypedConfigManagerInterface $typed_config) {
-    $this->storage = $storage;
+    $this->baseStorage = $storage;
     $this->eventDispatcher = $event_dispatcher;
     $this->typedConfigManager = $typed_config;
   }
@@ -67,72 +79,34 @@ public function __construct(StorageInterface $storage, EventDispatcherInterface
    * {@inheritdoc}
    */
   public function loadOverrides($names) {
-    $data = array();
-    $language_names = $this->getLanguageConfigNames($names);
-    if ($language_names) {
-      $data = $this->storage->readMultiple(array_values($language_names));
-      // Re-key the data array to use configuration names rather than override
-      // names.
-      $prefix_length = strlen(static::LANGUAGE_CONFIG_PREFIX . '.' . $this->language->id) + 1;
-      foreach ($data as $key => $value) {
-        unset($data[$key]);
-        $key = substr($key, $prefix_length);
-        $data[$key] = $value;
-      }
+    if ($this->language) {
+      $storage = $this->getStorage($this->language->getId());
+      return $storage->readMultiple($names);
     }
-    return $data;
+    return array();
   }
 
   /**
    * {@inheritdoc}
    */
   public function getOverride($langcode, $name) {
-    $override_name = $this->getLanguageConfigName($langcode, $name);
-    $overrides = $this->storage->read($override_name);
-    $config = new Config($override_name, $this->storage, $this->eventDispatcher, $this->typedConfigManager);
-    if (!empty($overrides)) {
-      $config->initWithData($overrides);
-    }
-    return $config;
-  }
-
-  /**
-   * Generate a list of configuration names based on base names.
-   *
-   * @param array $names
-   *   List of configuration names.
-   *
-   * @return array
-   *   List of configuration names for language override files if applicable.
-   */
-  protected function getLanguageConfigNames(array $names) {
-    $language_names = array();
-    if (isset($this->language)) {
-      foreach ($names as $name) {
-        if ($language_name = $this->getLanguageConfigName($this->language->id, $name)) {
-          $language_names[$name] = $language_name;
-        }
-      }
+    $storage = $this->getStorage($langcode);
+    $data = $storage->read($name);
+    $override = new LanguageConfigOverride($name, $storage, $this->typedConfigManager);
+    if (!empty($data)) {
+      $override->initWithData($data);
     }
-    return $language_names;
+    return $override;
   }
 
   /**
-   * Get language override name for given language and configuration name.
-   *
-   * @param string $langcode
-   *   Language code.
-   * @param string $name
-   *   Configuration name.
-   *
-   * @return bool|string
-   *   Configuration name or FALSE if not applicable.
+   * {@inheritdoc}
    */
-  protected function getLanguageConfigName($langcode, $name) {
-     if (strpos($name, static::LANGUAGE_CONFIG_PREFIX) === 0) {
-      return FALSE;
+  public function getStorage($langcode) {
+    if (!isset($this->storages[$langcode])) {
+      $this->storages[$langcode] = $this->baseStorage->createCollection($this->createConfigCollectionName($langcode));
     }
-    return static::LANGUAGE_CONFIG_PREFIX . '.' . $langcode . '.' . $name;
+    return $this->storages[$langcode];
   }
 
   /**
@@ -165,4 +139,48 @@ public function setLanguageFromDefault(LanguageDefault $language_default = NULL)
     return $this;
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public function installLanguageOverrides($langcode) {
+    /** @var \Drupal\Core\Config\ConfigInstallerInterface $config_installer */
+    $config_installer = \Drupal::service('config.installer');
+    $config_installer->installCollectionDefaultConfig($this->createConfigCollectionName($langcode));
+  }
+
+  /**
+   * Creates a configuration collection name based on a langcode.
+   *
+   * @param $langcode
+   *   The langcode.
+   *
+   * @return string
+   *   The configuration collection name for a langcode.
+   */
+  protected function createConfigCollectionName($langcode) {
+    return 'language.' . $langcode;
+  }
+
+  /**
+   * Reacts to the ConfigEvents::COLLECTION_NAMES event.
+   *
+   * @param \Drupal\Core\Config\ConfigCollectionNamesEvent $event
+   *   The configuration collection names event.
+   */
+  public function addCollectionNames(ConfigCollectionNamesEvent $event) {
+    $collections = array();
+    foreach (\Drupal::languageManager()->getLanguages() as $language) {
+      $collections[] = $this->createConfigCollectionName($language->getId());
+    }
+    $event->addCollectionNames($collections);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  static function getSubscribedEvents() {
+    $events[ConfigEvents::COLLECTION_NAMES][] = array('addCollectionNames');
+    return $events;
+  }
+
 }
diff --git a/core/modules/language/lib/Drupal/language/Config/LanguageConfigFactoryOverrideInterface.php b/core/modules/language/lib/Drupal/language/Config/LanguageConfigFactoryOverrideInterface.php
index 1c3de55..1d3a43b 100644
--- a/core/modules/language/lib/Drupal/language/Config/LanguageConfigFactoryOverrideInterface.php
+++ b/core/modules/language/lib/Drupal/language/Config/LanguageConfigFactoryOverrideInterface.php
@@ -17,11 +17,6 @@
 interface LanguageConfigFactoryOverrideInterface extends ConfigFactoryOverrideInterface {
 
   /**
-   * Prefix for all language configuration files.
-   */
-  const LANGUAGE_CONFIG_PREFIX = 'language.config';
-
-  /**
    * Gets the language object used to override configuration data.
    *
    * @return \Drupal\Core\Language\Language
@@ -62,4 +57,23 @@ public function setLanguageFromDefault(LanguageDefault $language_default = NULL)
    */
   public function getOverride($langcode, $name);
 
+  /**
+   * Returns the storage instance for a particular langcode.
+   *
+   * @param string $langcode
+   *   Language code.
+   *
+   * @return \Drupal\language\Config\LanguageOverrideStorageInterface
+   *   The language override storage object.
+   */
+  public function getStorage($langcode);
+
+  /**
+   * Installs available language configuration overrides for a given langcode.
+   *
+   * @param string $langcode
+   *   Language code.
+   */
+  public function installLanguageOverrides($langcode);
+
 }
diff --git a/core/modules/language/lib/Drupal/language/Config/LanguageConfigOverride.php b/core/modules/language/lib/Drupal/language/Config/LanguageConfigOverride.php
new file mode 100644
index 0000000..6ed2b11
--- /dev/null
+++ b/core/modules/language/lib/Drupal/language/Config/LanguageConfigOverride.php
@@ -0,0 +1,71 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\language\Config\LanguageConfigOverride.
+ */
+
+namespace Drupal\language\Config;
+
+use Drupal\Core\Config\StorableConfigBase;
+use Drupal\Core\Config\StorageInterface;
+use Drupal\Core\Config\TypedConfigManagerInterface;
+
+/**
+ * Defines language configuration overrides.
+ */
+class LanguageConfigOverride extends StorableConfigBase {
+
+  /**
+   * Constructs a language override object.
+   *
+   * @param string $name
+   *   The name of the configuration object being overridden.
+   * @param \Drupal\Core\Config\StorageInterface $storage
+   *   A storage controller object to use for reading and writing the
+   *   configuration override.
+   * @param \Drupal\Core\Config\TypedConfigManagerInterface $typed_config
+   *   The typed configuration manager service.
+   */
+  public function __construct($name, StorageInterface $storage, TypedConfigManagerInterface $typed_config) {
+    $this->name = $name;
+    $this->storage = $storage;
+    $this->typedConfigManager = $typed_config;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function save() {
+    // Validate the configuration object name before saving.
+    static::validateName($this->name);
+
+    // If there is a schema for this configuration object, cast all values to
+    // conform to the schema.
+    if ($this->typedConfigManager->hasConfigSchema($this->name)) {
+      // Ensure that the schema wrapper has the latest data.
+      $this->schemaWrapper = NULL;
+      foreach ($this->data as $key => $value) {
+        $this->data[$key] = $this->castValue($key, $value);
+      }
+    }
+
+    $this->storage->write($this->name, $this->data);
+    $this->isNew = FALSE;
+    $this->originalData = $this->data;
+    return $this;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function delete() {
+    // @todo Consider to remove the pruning of data for Config::delete().
+    $this->data = array();
+    $this->storage->delete($this->name);
+    $this->isNew = TRUE;
+    $this->originalData = $this->data;
+    return $this;
+  }
+
+}
diff --git a/core/modules/language/lib/Drupal/language/ConfigurableLanguageManager.php b/core/modules/language/lib/Drupal/language/ConfigurableLanguageManager.php
index 101449c..b28e02b 100644
--- a/core/modules/language/lib/Drupal/language/ConfigurableLanguageManager.php
+++ b/core/modules/language/lib/Drupal/language/ConfigurableLanguageManager.php
@@ -410,6 +410,13 @@ public function getLanguageConfigOverride($langcode, $name) {
   /**
    * {@inheritdoc}
    */
+  public function getLanguageConfigOverrideStorage($langcode) {
+    return $this->configFactoryOverride->getStorage($langcode);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
   public function getStandardLanguageListWithoutConfigured() {
     $languages = $this->getLanguages();
     $predefined = $this->getStandardLanguageList();
diff --git a/core/modules/language/lib/Drupal/language/ConfigurableLanguageManagerInterface.php b/core/modules/language/lib/Drupal/language/ConfigurableLanguageManagerInterface.php
index 9bbf2ce..0007524 100644
--- a/core/modules/language/lib/Drupal/language/ConfigurableLanguageManagerInterface.php
+++ b/core/modules/language/lib/Drupal/language/ConfigurableLanguageManagerInterface.php
@@ -91,12 +91,24 @@ public function updateLockedLanguageWeights();
    * @param string $name
    *   The language configuration object name.
    *
-   * @return \Drupal\Core\Config\Config
+   * @return \Drupal\language\Config\LanguageConfigOverride
    *   The language config override object.
    */
   public function getLanguageConfigOverride($langcode, $name);
 
   /**
+   * Gets a language config override storage object.
+   *
+   * @param string $langcode
+   *   The language code for the override.
+   *
+   * @param \Drupal\Core\Config\StorageInterface $storage
+   *   A storage object to use for reading and writing the
+   *   configuration override.
+   */
+  public function getLanguageConfigOverrideStorage($langcode);
+
+  /**
    * Returns the standard language list excluding already configured languages.
    *
    * @return array
diff --git a/core/modules/language/lib/Drupal/language/Tests/LanguageConfigOverrideImportTest.php b/core/modules/language/lib/Drupal/language/Tests/LanguageConfigOverrideImportTest.php
new file mode 100644
index 0000000..9df51e3
--- /dev/null
+++ b/core/modules/language/lib/Drupal/language/Tests/LanguageConfigOverrideImportTest.php
@@ -0,0 +1,67 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\language\Tests\LanguageConfigOverrideImportTest.
+ */
+
+namespace Drupal\language\Tests;
+
+use Drupal\Core\Config\FileStorage;
+use Drupal\Core\Language\Language;
+use Drupal\simpletest\WebTestBase;
+
+class LanguageConfigOverrideImportTest extends WebTestBase {
+
+  /**
+   * Modules to enable.
+   *
+   * @var array
+   */
+  public static $modules = array('language', 'config', 'locale', 'config_translation');
+
+  public static function getInfo() {
+    return array(
+      'name' => 'Language config override synchronize',
+      'description' => 'Ensures the language config overrides can be synchronized.',
+      'group' => 'Language',
+    );
+  }
+
+  /**
+   *
+   */
+  public function testConfigOverrideImport() {
+    language_save(new Language(array(
+      'name' => 'French',
+      'id' => 'fr',
+    )));
+    /* @var \Drupal\Core\Config\StorageInterface $staging */
+    $staging = \Drupal::service('config.storage.staging');
+    $this->copyConfig(\Drupal::service('config.storage'), $staging);
+
+    \Drupal::moduleHandler()->uninstall(array('language'));
+    // Ensure that the current site has no overrides registered to the
+    // ConfigFactory.
+    $this->rebuildContainer();
+
+    /* @var \Drupal\Core\Config\StorageInterface $override_staging */
+    $override_staging = new FileStorage(config_get_config_directory(CONFIG_STAGING_DIRECTORY) . '/language/fr');
+    // Create some overrides in staging.
+    $override_staging->write('system.site', array('name' => 'FR default site name'));
+    $override_staging->write('system.maintenance', array('message' => 'FR message: @site is currently under maintenance. We should be back shortly. Thank you for your patience'));
+
+    $this->configImporter()->import();
+    $this->rebuildContainer();
+    \Drupal::service('router.builder')->rebuild();
+
+    $override = \Drupal::languageManager()->getLanguageConfigOverride('fr', 'system.site');
+    $this->assertEqual('FR default site name', $override->get('name'));
+    $this->drupalGet('fr');
+    $this->assertText('FR default site name');
+
+    $this->drupalLogin($this->root_user);
+    $this->drupalGet('admin/config/development/maintenance/translate/fr/edit');
+    $this->assertText('FR message: @site is currently under maintenance. We should be back shortly. Thank you for your patience');
+  }
+}
diff --git a/core/modules/locale/lib/Drupal/locale/LocaleConfigManager.php b/core/modules/locale/lib/Drupal/locale/LocaleConfigManager.php
index 3c0dc57..f731b13 100644
--- a/core/modules/locale/lib/Drupal/locale/LocaleConfigManager.php
+++ b/core/modules/locale/lib/Drupal/locale/LocaleConfigManager.php
@@ -230,9 +230,9 @@ public function getStringNames(array $lids) {
    *   Language code to delete.
    */
   public function deleteLanguageTranslations($langcode) {
-    $locale_name = LanguageConfigFactoryOverrideInterface::LANGUAGE_CONFIG_PREFIX . '.' . $langcode . '.';
-    foreach ($this->configStorage->listAll($locale_name) as $name) {
-      $this->configStorage->delete($name);
+    $storage = $this->languageManager->getLanguageConfigOverrideStorage($langcode);
+    foreach ($storage->listAll() as $name) {
+      $this->languageManager->getLanguageConfigOverride($langcode, $name)->delete();
     }
   }
 
diff --git a/core/modules/locale/lib/Drupal/locale/Tests/LocaleConfigManagerTest.php b/core/modules/locale/lib/Drupal/locale/Tests/LocaleConfigManagerTest.php
index bdde87f..50cbc7d 100644
--- a/core/modules/locale/lib/Drupal/locale/Tests/LocaleConfigManagerTest.php
+++ b/core/modules/locale/lib/Drupal/locale/Tests/LocaleConfigManagerTest.php
@@ -42,7 +42,7 @@ public function testHasTranslation() {
     $this->installConfig(array('locale_test'));
     $locale_config_manager = \Drupal::service('locale.config.typed');
 
-    $language = new Language(array('id' => 'de'));
+    $language = language_save(new Language(array('id' => 'de')));
     $result = $locale_config_manager->hasTranslation('locale_test.no_translation', $language);
     $this->assertFalse($result, 'There is no translation for locale_test.no_translation configuration.');
 
diff --git a/core/modules/locale/tests/modules/locale_test/config/install/language.config.de.locale_test.translation.yml b/core/modules/locale/tests/modules/locale_test/config/install/language/de/locale_test.translation.yml
similarity index 100%
rename from core/modules/locale/tests/modules/locale_test/config/install/language.config.de.locale_test.translation.yml
rename to core/modules/locale/tests/modules/locale_test/config/install/language/de/locale_test.translation.yml
diff --git a/core/modules/simpletest/lib/Drupal/simpletest/TestBase.php b/core/modules/simpletest/lib/Drupal/simpletest/TestBase.php
index 627f6dc..19dd044 100644
--- a/core/modules/simpletest/lib/Drupal/simpletest/TestBase.php
+++ b/core/modules/simpletest/lib/Drupal/simpletest/TestBase.php
@@ -1481,7 +1481,8 @@ public function configImporter() {
       // Set up the ConfigImporter object for testing.
       $storage_comparer = new StorageComparer(
         $this->container->get('config.storage.staging'),
-        $this->container->get('config.storage')
+        $this->container->get('config.storage'),
+        $this->container->get('config.manager')
       );
       $this->configImporter = new ConfigImporter(
         $storage_comparer,
diff --git a/core/modules/system/tests/modules/menu_test/config/install/language.config.nl.menu_test.menu_item.yml b/core/modules/system/tests/modules/menu_test/config/install/language/nl/menu_test.menu_item.yml
similarity index 100%
rename from core/modules/system/tests/modules/menu_test/config/install/language.config.nl.menu_test.menu_item.yml
rename to core/modules/system/tests/modules/menu_test/config/install/language/nl/menu_test.menu_item.yml
diff --git a/core/modules/tour/tests/tour_test/config/install/language.config.it.tour.tour.tour-test.yml b/core/modules/tour/tests/tour_test/config/install/language/it/tour.tour.tour-test.yml
similarity index 100%
rename from core/modules/tour/tests/tour_test/config/install/language.config.it.tour.tour.tour-test.yml
rename to core/modules/tour/tests/tour_test/config/install/language/it/tour.tour.tour-test.yml
diff --git a/core/tests/Drupal/Tests/Core/Config/CachedStorageTest.php b/core/tests/Drupal/Tests/Core/Config/CachedStorageTest.php
index 6c60af4..a66d55b 100644
--- a/core/tests/Drupal/Tests/Core/Config/CachedStorageTest.php
+++ b/core/tests/Drupal/Tests/Core/Config/CachedStorageTest.php
@@ -6,7 +6,6 @@
 use Drupal\Core\Config\CachedStorage;
 use Drupal\Core\Cache\MemoryBackend;
 use Drupal\Core\Cache\NullBackend;
-use Drupal\Core\Cache\CacheBackendInterface;
 
 /**
  * Tests the interaction of cache and file storage in CachedStorage.
@@ -15,6 +14,11 @@
  */
 class CachedStorageTest extends UnitTestCase {
 
+  /**
+   * @var \Drupal\Core\Cache\CacheFactoryInterface|\PHPUnit_Framework_MockObject_MockObject
+   */
+  protected $cacheFactory;
+
   public static function getInfo() {
     return array(
       'name' => 'Config cached storage test',
@@ -23,6 +27,10 @@ public static function getInfo() {
     );
   }
 
+  public function setUp() {
+    $this->cacheFactory = $this->getMock('Drupal\Core\Cache\CacheFactoryInterface');
+  }
+
   /**
    * Test listAll static cache.
    */
@@ -37,7 +45,11 @@ public function testListAllStaticCache() {
       ->will($this->returnValue($response));
 
     $cache = new NullBackend(__FUNCTION__);
-    $cachedStorage = new CachedStorage($storage, $cache);
+    $this->cacheFactory->expects($this->once())
+      ->method('get')
+      ->with('config')
+      ->will($this->returnValue($cache));
+    $cachedStorage = new CachedStorage($storage, $this->cacheFactory);
     $this->assertEquals($response, $cachedStorage->listAll($prefix));
     $this->assertEquals($response, $cachedStorage->listAll($prefix));
   }
@@ -53,7 +65,11 @@ public function testListAllPrimedPersistentCache() {
     $response = array("$prefix." . $this->randomName(), "$prefix." . $this->randomName());
     $cache = new MemoryBackend(__FUNCTION__);
     $cache->set('find:' . $prefix, $response);
-    $cachedStorage = new CachedStorage($storage, $cache);
+    $this->cacheFactory->expects($this->once())
+      ->method('get')
+      ->with('config')
+      ->will($this->returnValue($cache));
+    $cachedStorage = new CachedStorage($storage, $this->cacheFactory);
     $this->assertEquals($response, $cachedStorage->listAll($prefix));
   }
 
@@ -79,7 +95,11 @@ public function testGetMultipleOnPrimedCache() {
     foreach ($configCacheValues as $key => $value) {
       $cache->set($key, $value);
     }
-    $cachedStorage = new CachedStorage($storage, $cache);
+    $this->cacheFactory->expects($this->once())
+      ->method('get')
+      ->with('config')
+      ->will($this->returnValue($cache));
+    $cachedStorage = new CachedStorage($storage, $this->cacheFactory);
     $this->assertEquals($configCacheValues, $cachedStorage->readMultiple($configNames));
   }
 
@@ -119,7 +139,11 @@ public function testGetMultipleOnPartiallyPrimedCache() {
       ->with(array(2 => $configNames[2], 4 => $configNames[4]))
       ->will($this->returnValue($response));
 
-    $cachedStorage = new CachedStorage($storage, $cache);
+    $this->cacheFactory->expects($this->once())
+      ->method('get')
+      ->with('config')
+      ->will($this->returnValue($cache));
+    $cachedStorage = new CachedStorage($storage, $this->cacheFactory);
     $expected_data = $configCacheValues + array($configNames[2] => $config_exists_not_cached_data);
     $this->assertEquals($expected_data, $cachedStorage->readMultiple($configNames));
 
@@ -143,7 +167,11 @@ public function testReadNonExistentFileCacheMiss() {
             ->method('read')
             ->with($name)
             ->will($this->returnValue(FALSE));
-    $cachedStorage = new CachedStorage($storage, $cache);
+    $this->cacheFactory->expects($this->once())
+      ->method('get')
+      ->with('config')
+      ->will($this->returnValue($cache));
+    $cachedStorage = new CachedStorage($storage, $this->cacheFactory);
 
     $this->assertFalse($cachedStorage->read($name));
 
@@ -163,7 +191,11 @@ public function testReadNonExistentFileCached() {
     $storage = $this->getMock('Drupal\Core\Config\StorageInterface');
     $storage->expects($this->never())
             ->method('read');
-    $cachedStorage = new CachedStorage($storage, $cache);
+    $this->cacheFactory->expects($this->once())
+      ->method('get')
+      ->with('config')
+      ->will($this->returnValue($cache));
+    $cachedStorage = new CachedStorage($storage, $this->cacheFactory);
     $this->assertFalse($cachedStorage->read($name));
   }
 
diff --git a/core/tests/Drupal/Tests/Core/Config/StorageComparerTest.php b/core/tests/Drupal/Tests/Core/Config/StorageComparerTest.php
index 500c06f..178be29 100644
--- a/core/tests/Drupal/Tests/Core/Config/StorageComparerTest.php
+++ b/core/tests/Drupal/Tests/Core/Config/StorageComparerTest.php
@@ -30,6 +30,11 @@ class StorageComparerTest extends UnitTestCase {
   protected $targetStorage;
 
   /**
+   * @var \Drupal\Core\Config\ConfigManager|\PHPUnit_Framework_MockObject_MockObject
+   */
+  protected $configManager;
+
+  /**
    * The storage comparer to test.
    *
    * @var \Drupal\Core\Config\StorageComparer
@@ -54,7 +59,8 @@ public static function getInfo() {
   public function setUp() {
     $this->sourceStorage = $this->getMock('Drupal\Core\Config\StorageInterface');
     $this->targetStorage = $this->getMock('Drupal\Core\Config\StorageInterface');
-    $this->storageComparer = new StorageComparer($this->sourceStorage, $this->targetStorage);
+    $this->configManager = $this->getMock('Drupal\Core\Config\ConfigManagerInterface');
+    $this->storageComparer = new StorageComparer($this->sourceStorage, $this->targetStorage, $this->configManager);
   }
 
   protected function getConfigData() {
@@ -123,6 +129,15 @@ public function testCreateChangelistNoChange() {
     $this->targetStorage->expects($this->once())
       ->method('readMultiple')
       ->will($this->returnValue($config_data));
+    $this->sourceStorage->expects($this->once())
+      ->method('getAllCollectionNames')
+      ->will($this->returnValue(array()));
+    $this->targetStorage->expects($this->once())
+      ->method('getAllCollectionNames')
+      ->will($this->returnValue(array()));
+    $this->configManager->expects($this->any())
+      ->method('supportsConfigurationEntities')
+      ->will($this->returnValue(TRUE));
 
     $this->storageComparer->createChangelist();
     $this->assertEmpty($this->storageComparer->getChangelist('create'));
@@ -151,6 +166,15 @@ public function testCreateChangelistCreate() {
     $this->targetStorage->expects($this->once())
       ->method('readMultiple')
       ->will($this->returnValue($target_data));
+    $this->sourceStorage->expects($this->once())
+      ->method('getAllCollectionNames')
+      ->will($this->returnValue(array()));
+    $this->targetStorage->expects($this->once())
+      ->method('getAllCollectionNames')
+      ->will($this->returnValue(array()));
+    $this->configManager->expects($this->any())
+      ->method('supportsConfigurationEntities')
+      ->will($this->returnValue(TRUE));
 
     $this->storageComparer->createChangelist();
     $expected = array(
@@ -184,6 +208,15 @@ public function testCreateChangelistDelete() {
     $this->targetStorage->expects($this->once())
       ->method('readMultiple')
       ->will($this->returnValue($target_data));
+    $this->sourceStorage->expects($this->once())
+      ->method('getAllCollectionNames')
+      ->will($this->returnValue(array()));
+    $this->targetStorage->expects($this->once())
+      ->method('getAllCollectionNames')
+      ->will($this->returnValue(array()));
+    $this->configManager->expects($this->any())
+      ->method('supportsConfigurationEntities')
+      ->will($this->returnValue(TRUE));
 
     $this->storageComparer->createChangelist();
     $expected = array(
@@ -217,6 +250,15 @@ public function testCreateChangelistUpdate() {
     $this->targetStorage->expects($this->once())
       ->method('readMultiple')
       ->will($this->returnValue($target_data));
+    $this->sourceStorage->expects($this->once())
+      ->method('getAllCollectionNames')
+      ->will($this->returnValue(array()));
+    $this->targetStorage->expects($this->once())
+      ->method('getAllCollectionNames')
+      ->will($this->returnValue(array()));
+    $this->configManager->expects($this->any())
+      ->method('supportsConfigurationEntities')
+      ->will($this->returnValue(TRUE));
 
     $this->storageComparer->createChangelist();
     $expected = array(
