diff --git a/core/lib/Drupal/Core/Config/CachedStorage.php b/core/lib/Drupal/Core/Config/CachedStorage.php
index 1ff4046..c122260 100644
--- a/core/lib/Drupal/Core/Config/CachedStorage.php
+++ b/core/lib/Drupal/Core/Config/CachedStorage.php
@@ -67,7 +67,7 @@ public function exists($name) {
    * Implements Drupal\Core\Config\StorageInterface::read().
    */
   public function read($name) {
-    if ($cache = $this->cache->get($name)) {
+    if ($cache = $this->cache->get($this->getCacheKey($name))) {
       // The cache contains either the cached configuration data or FALSE
       // if the configuration file does not exist.
       return $cache->data;
@@ -75,7 +75,7 @@ public function read($name) {
     // Read from the storage on a cache miss and cache the data. Also cache
     // information about missing configuration objects.
     $data = $this->storage->read($name);
-    $this->cache->set($name, $data);
+    $this->cache->set($this->getCacheKey($name), $data);
     return $data;
   }
 
@@ -87,20 +87,22 @@ public function readMultiple(array $names) {
     // The names array is passed by reference and will only contain the names of
     // config object not found after the method call.
     // @see \Drupal\Core\Cache\CacheBackendInterface::getMultiple()
-    $cached_list = $this->cache->getMultiple($names);
+    $cids = $this->getCacheKeys($names);
+    $cached_list = $this->cache->getMultiple($cids);
 
-    if (!empty($names)) {
+    if (!empty($cids)) {
+      $names = $this->getNamesFromCacheKeys($cids);
       $list = $this->storage->readMultiple($names);
       // Cache configuration objects that were loaded from the storage, cache
       // missing configuration objects as an explicit FALSE.
       foreach ($names as $name) {
-        $this->cache->set($name, isset($list[$name]) ? $list[$name] : FALSE);
+        $this->cache->set($this->getCacheKey($name), isset($list[$name]) ? $list[$name] : FALSE);
       }
     }
 
     // Add the configuration objects from the cache to the list.
-    foreach ($cached_list as $name => $cache) {
-      $list[$name] = $cache->data;
+    foreach ($cached_list as $cid => $cache) {
+      $list[$this->getNameFromCacheKey($cid)] = $cache->data;
     }
 
     // Ensure that only existing configuration objects are returned, filter out
@@ -115,7 +117,7 @@ public function write($name, array $data) {
     if ($this->storage->write($name, $data)) {
       // While not all written data is read back, setting the cache instead of
       // just deleting it avoids cache rebuild stampedes.
-      $this->cache->set($name, $data);
+      $this->cache->set($this->getCacheKey($name), $data);
       Cache::deleteTags(array($this::FIND_BY_PREFIX_CACHE_TAG => TRUE));
       $this->findByPrefixCache = array();
       return TRUE;
@@ -130,7 +132,7 @@ public function delete($name) {
     // If the cache was the first to be deleted, another process might start
     // rebuilding the cache before the storage is gone.
     if ($this->storage->delete($name)) {
-      $this->cache->delete($name);
+      $this->cache->delete($this->getCacheKey($name));
       Cache::deleteTags(array($this::FIND_BY_PREFIX_CACHE_TAG => TRUE));
       $this->findByPrefixCache = array();
       return TRUE;
@@ -145,8 +147,8 @@ public function rename($name, $new_name) {
     // If the cache was the first to be deleted, another process might start
     // rebuilding the cache before the storage is renamed.
     if ($this->storage->rename($name, $new_name)) {
-      $this->cache->delete($name);
-      $this->cache->delete($new_name);
+      $this->cache->delete($this->getCacheKey($name));
+      $this->cache->delete($this->getCacheKey($new_name));
       Cache::deleteTags(array($this::FIND_BY_PREFIX_CACHE_TAG => TRUE));
       $this->findByPrefixCache = array();
       return TRUE;
@@ -199,13 +201,14 @@ protected function findByPrefix($prefix) {
     if (!isset($this->findByPrefixCache[$prefix])) {
       // The : character is not allowed in config file names, so this can not
       // conflict.
-      if ($cache = $this->cache->get('find:' . $prefix)) {
+      $cache_key = $this->getCacheKey('find:' . $prefix);
+      if ($cache = $this->cache->get($cache_key)) {
         $this->findByPrefixCache[$prefix] = $cache->data;
       }
       else {
         $this->findByPrefixCache[$prefix] = $this->storage->listAll($prefix);
         $this->cache->set(
-          'find:' . $prefix,
+          $cache_key,
           $this->findByPrefixCache[$prefix],
           Cache::PERMANENT,
           array($this::FIND_BY_PREFIX_CACHE_TAG => TRUE)
@@ -221,7 +224,7 @@ protected function findByPrefix($prefix) {
   public function deleteAll($prefix = '') {
     // If the cache was the first to be deleted, another process might start
     // rebuilding the cache before the storage is renamed.
-    $cids = $this->storage->listAll($prefix);
+    $cids = $this->getCacheKeys($this->storage->listAll($prefix));
     if ($this->storage->deleteAll($prefix)) {
       $this->cache->deleteMultiple($cids);
       return TRUE;
@@ -235,4 +238,64 @@ public function deleteAll($prefix = '') {
   public function resetListCache() {
     $this->findByPrefixCache = array();
   }
+
+  /**
+   * Gets the cache key for a configuration object name.
+   *
+   * In the default implementation of CachedStorage this simply returns the
+   * name. In more complex implementations this allows different versions of
+   * the same configuration object to cached. Since the maximum length of a
+   * configuration object name is 250 characters this should never add more than
+   * 5 characters to the cache key.
+   *
+   * @see \Drupal\language\Config\LanguageStorage::getCacheKey()
+   *
+   * @param string $name
+   *   The configuration object name.
+   *
+   * @return string
+   *   The cache key.
+   */
+  protected function getCacheKey($name) {
+    return $name;
+  }
+
+  /**
+   * Gets the cache keys for an array of configuration object names.
+   *
+   * @param array $names
+   *   The configuration object names.
+   *
+   * @return array
+   *   An array of cache keys.
+   */
+  protected function getCacheKeys(array $names) {
+    return $names;
+  }
+
+  /**
+   * Converts a cache key into a configuration object name.
+   *
+   * @param string $key
+   *   The cache key.
+   *
+   * @return string
+   *   The configuration object name.
+   */
+  protected function getNameFromCacheKey($key) {
+    return $key;
+  }
+
+  /**
+   * Converts an array of cache keys into an array of configuration object names.
+   *
+   * @param string $key
+   *   The cache key.
+   *
+   * @return string
+   *   The configuration object name.
+   */
+  protected function getNamesFromCacheKeys($keys) {
+    return $keys;
+  }
 }
diff --git a/core/lib/Drupal/Core/Config/Config.php b/core/lib/Drupal/Core/Config/Config.php
index e000200..e864af2 100644
--- a/core/lib/Drupal/Core/Config/Config.php
+++ b/core/lib/Drupal/Core/Config/Config.php
@@ -15,7 +15,6 @@
 use Drupal\Core\TypedData\PrimitiveInterface;
 use Drupal\Core\TypedData\Type\FloatInterface;
 use Drupal\Core\TypedData\Type\IntegerInterface;
-use Drupal\Core\Language\Language;
 use Symfony\Component\EventDispatcher\EventDispatcherInterface;
 
 /**
@@ -43,13 +42,6 @@ class Config extends DependencySerialization {
   protected $eventDispatcher;
 
   /**
-   * The language object used to override configuration data.
-   *
-   * @var Drupal\Core\Language\Language
-   */
-  protected $language;
-
-  /**
    * The name of the configuration object.
    *
    * @var string
@@ -80,21 +72,14 @@ class Config extends DependencySerialization {
   /**
    * The current runtime data.
    *
-   * The configuration data from storage merged with language, module and
-   * settings overrides.
+   * The configuration data from storage merged with module and settings
+   * overrides.
    *
    * @var array
    */
   protected $overriddenData;
 
   /**
-   * The current language overrides.
-   *
-   * @var array
-   */
-  protected $languageOverrides;
-
-  /**
    * The current module overrides.
    *
    * @var array
@@ -130,19 +115,17 @@ class Config extends DependencySerialization {
    * @param \Drupal\Core\Config\StorageInterface $storage
    *   A storage controller object to use for reading and writing the
    *   configuration data.
-   * @param \Symfony\Component\EventDispatcher\EventDispatcherInterface $event_dispatcher
-   *   An event dispatcher instance to use for configuration events.
    * @param \Drupal\Core\Config\TypedConfigManager $typed_config
    *   The typed configuration manager service.
-   * @param \Drupal\Core\Language\Language $language
-   *   The language object used to override configuration data.
+   * @param \Symfony\Component\EventDispatcher\EventDispatcherInterface $event_dispatcher
+   *   An event dispatcher instance to use for configuration events. Defaults to
+   *   NULL which allows usage without firing events.
    */
-  public function __construct($name, StorageInterface $storage, EventDispatcherInterface $event_dispatcher, TypedConfigManager $typed_config, Language $language = NULL) {
+  public function __construct($name, StorageInterface $storage, TypedConfigManager $typed_config, EventDispatcherInterface $event_dispatcher = NULL) {
     $this->name = $name;
     $this->storage = $storage;
     $this->eventDispatcher = $event_dispatcher;
     $this->typedConfigManager = $typed_config;
-    $this->language = $language;
   }
 
   /**
@@ -156,7 +139,6 @@ public function __construct($name, StorageInterface $storage, EventDispatcherInt
    */
   public function initWithData(array $data) {
     $this->settingsOverrides = array();
-    $this->languageOverrides = array();
     $this->moduleOverrides = array();
     $this->isNew = FALSE;
     $this->replaceData($data);
@@ -337,36 +319,19 @@ public function setModuleOverride(array $data) {
   }
 
   /**
-   * Sets language overrides for this configuration object.
-   *
-   * @param array $data
-   *   The overridden values of the configuration data.
-   *
-   * @return \Drupal\Core\Config\Config
-   *   The configuration object.
-   */
-  public function setLanguageOverride(array $data) {
-    $this->languageOverrides = $data;
-    $this->resetOverriddenData();
-    return $this;
-  }
-
-  /**
    * Sets the current data for this configuration object.
    *
-   * Configuration overrides operate at three distinct layers: language, modules
-   * and settings.php, with the last of these taking precedence. Overrides in
-   * settings.php take precedence over values provided by modules. Overrides
-   * provided by modules take precedence over language.
+   * Configuration overrides operate at two distinct layers: modules and
+   * settings.php, with the last of these taking precedence. Overrides in
+   * settings.php take precedence over values provided by modules. Precedence
+   * or different module overrides is determined by the priority of the
+   * config.factory.override tagged service.
    *
    * @return \Drupal\Core\Config\Config
    *   The configuration object.
    */
   protected function setOverriddenData() {
     $this->overriddenData = $this->data;
-    if (isset($this->languageOverrides) && is_array($this->languageOverrides)) {
-      $this->overriddenData = NestedArray::mergeDeepArray(array($this->overriddenData, $this->languageOverrides), TRUE);
-    }
     if (isset($this->moduleOverrides) && is_array($this->moduleOverrides)) {
       $this->overriddenData = NestedArray::mergeDeepArray(array($this->overriddenData, $this->moduleOverrides), TRUE);
     }
@@ -458,7 +423,9 @@ public function save() {
 
     $this->storage->write($this->name, $this->data);
     $this->isNew = FALSE;
-    $this->eventDispatcher->dispatch(ConfigEvents::SAVE, new ConfigCrudEvent($this));
+    if (isset($this->eventDispatcher)) {
+      $this->eventDispatcher->dispatch(ConfigEvents::SAVE, new ConfigCrudEvent($this));
+    }
     $this->originalData = $this->data;
     return $this;
   }
@@ -475,7 +442,9 @@ public function delete() {
     $this->storage->delete($this->name);
     $this->isNew = TRUE;
     $this->resetOverriddenData();
-    $this->eventDispatcher->dispatch(ConfigEvents::DELETE, new ConfigCrudEvent($this));
+    if (isset($this->eventDispatcher)) {
+      $this->eventDispatcher->dispatch(ConfigEvents::DELETE, new ConfigCrudEvent($this));
+    }
     $this->originalData = $this->data;
     return $this;
   }
@@ -586,15 +555,6 @@ protected function castValue($key, $value) {
   }
 
   /**
-   * Returns the language object for this Config object.
-   *
-   * @return \Drupal\Core\Language\Language
-   */
-  public function getLanguage() {
-    return $this->language;
-  }
-
-  /**
    * Gets the raw data without overrides.
    *
    * @return array
@@ -625,9 +585,6 @@ public function getOriginal($key = '', $apply_overrides = TRUE) {
     $original_data = $this->originalData;
     if ($apply_overrides) {
       // Apply overrides.
-      if (isset($this->languageOverrides) && is_array($this->languageOverrides)) {
-        $original_data = NestedArray::mergeDeepArray(array($original_data, $this->languageOverrides), TRUE);
-      }
       if (isset($this->moduleOverrides) && is_array($this->moduleOverrides)) {
         $original_data = NestedArray::mergeDeepArray(array($original_data, $this->moduleOverrides), TRUE);
       }
diff --git a/core/lib/Drupal/Core/Config/ConfigEvents.php b/core/lib/Drupal/Core/Config/ConfigEvents.php
index 839b189..48f4eeb 100644
--- a/core/lib/Drupal/Core/Config/ConfigEvents.php
+++ b/core/lib/Drupal/Core/Config/ConfigEvents.php
@@ -35,13 +35,6 @@
   const RENAME = 'config.rename';
 
   /**
-   * Name of event fired when collecting overrides for configuration objects.
-   *
-   * @see \Drupal\Core\Config\ConfigFactory::loadModuleOverrides().
-   */
-  const MODULE_OVERRIDES = 'config.module.overrides';
-
-  /**
    * Name of event fired when validating in the configuration import process.
    *
    * @see \Drupal\Core\Config\ConfigImporter::validate().
diff --git a/core/lib/Drupal/Core/Config/ConfigFactory.php b/core/lib/Drupal/Core/Config/ConfigFactory.php
index 3d26c78..5c4ef49 100644
--- a/core/lib/Drupal/Core/Config/ConfigFactory.php
+++ b/core/lib/Drupal/Core/Config/ConfigFactory.php
@@ -7,9 +7,7 @@
 
 namespace Drupal\Core\Config;
 
-use Drupal\Core\Language\Language;
-use Drupal\Core\Language\LanguageDefault;
-use Symfony\Component\EventDispatcher\EventDispatcher;
+use Drupal\Component\Utility\NestedArray;
 use Symfony\Component\EventDispatcher\EventDispatcherInterface;
 use Symfony\Component\EventDispatcher\EventSubscriberInterface;
 
@@ -50,13 +48,6 @@ class ConfigFactory implements ConfigFactoryInterface, EventSubscriberInterface
   protected $useOverrides = TRUE;
 
   /**
-   * The language object used to override configuration data.
-   *
-   * @var \Drupal\Core\Language\Language
-   */
-  protected $language;
-
-  /**
    * Cached configuration objects.
    *
    * @var \Drupal\Core\Config\Config[]
@@ -71,6 +62,20 @@ class ConfigFactory implements ConfigFactoryInterface, EventSubscriberInterface
   protected $typedConfigManager;
 
   /**
+   * An array of config factory override objects grouped by priority.
+   *
+   * @var array
+   */
+  protected $configFactoryOverrides = array();
+
+  /**
+   * An array of sorted config factory override objects.
+   *
+   * @var array|\Drupal\Core\Config\ConfigFactoryOverrideInterface[]
+   */
+  protected $sortedConfigFactoryOverrides;
+
+  /**
    * Constructs the Config factory.
    *
    * @param \Drupal\Core\Config\StorageInterface $storage
@@ -118,23 +123,13 @@ public function get($name) {
         // If the configuration object does not exist in the configuration
         // storage or static cache create a new object and add it to the static
         // cache.
-        $this->cache[$cache_key] = new Config($name, $this->storage, $this->eventDispatcher, $this->typedConfigManager, $this->language);
+        $this->cache[$cache_key] = new Config($name, $this->storage, $this->typedConfigManager, $this->eventDispatcher);
 
-        if ($this->canOverride($name)) {
-          // Get and apply any language overrides.
-          if ($this->language) {
-            $language_overrides = $this->storage->read($this->getLanguageConfigName($this->language->id, $name));
-          }
-          else {
-            $language_overrides = FALSE;
-          }
-          if (is_array($language_overrides)) {
-            $this->cache[$cache_key]->setLanguageOverride($language_overrides);
-          }
-          // Get and apply any module overrides.
-          $module_overrides = $this->loadModuleOverrides(array($name));
-          if (isset($module_overrides[$name])) {
-            $this->cache[$cache_key]->setModuleOverride($module_overrides[$name]);
+        if ($this->useOverrides) {
+          // Get and apply any overrides.
+          $overrides = $this->loadOverrides(array($name));
+          if (isset($overrides[$name])) {
+            $this->cache[$cache_key]->setModuleOverride($overrides[$name]);
           }
           // Apply any settings.php overrides.
           if (isset($GLOBALS['config'][$name])) {
@@ -166,38 +161,19 @@ public function loadMultiple(array $names) {
     if (!empty($names)) {
       // Initialise override information.
       $module_overrides = array();
-      $language_names = array();
-
-      if ($this->useOverrides) {
-        // In order to make just one call to storage, add in language names.
-        // Keep track of them separately, so we can get language override data
-        // returned from storage and set it on new Config objects.
-        $language_names = $this->getLanguageConfigNames($names);
-      }
-
-      $storage_data = $this->storage->readMultiple(array_merge($names, array_values($language_names)));
+      $storage_data = $this->storage->readMultiple($names);
 
       if ($this->useOverrides && !empty($storage_data)) {
-        // Only fire module override event if we have configuration to override.
-        $module_overrides = $this->loadModuleOverrides($names);
+        // Only get module overrides if we have configuration to override.
+        $module_overrides = $this->loadOverrides($names);
       }
 
       foreach ($storage_data as $name => $data) {
-        if (in_array($name, $language_names)) {
-          // Language override configuration is used to override other
-          // configuration. Therefore, when it has been added to the
-          // $storage_data it is not statically cached in the config factory or
-          // overridden in any way.
-          continue;
-        }
         $cache_key = $this->getCacheKey($name);
 
-        $this->cache[$cache_key] = new Config($name, $this->storage, $this->eventDispatcher, $this->typedConfigManager, $this->language);
+        $this->cache[$cache_key] = new Config($name, $this->storage, $this->typedConfigManager, $this->eventDispatcher);
         $this->cache[$cache_key]->initWithData($data);
-        if ($this->canOverride($name)) {
-          if (isset($language_names[$name]) && isset($storage_data[$language_names[$name]])) {
-            $this->cache[$cache_key]->setLanguageOverride($storage_data[$language_names[$name]]);
-          }
+        if ($this->useOverrides) {
           if (isset($module_overrides[$name])) {
             $this->cache[$cache_key]->setModuleOverride($module_overrides[$name]);
           }
@@ -221,10 +197,14 @@ public function loadMultiple(array $names) {
    * @return array
    *   An array of overrides keyed by the configuration object name.
    */
-  protected function loadModuleOverrides(array $names) {
-    $configOverridesEvent = new ConfigModuleOverridesEvent($names, $this->language);
-    $this->eventDispatcher->dispatch(ConfigEvents::MODULE_OVERRIDES, $configOverridesEvent);
-    return $configOverridesEvent->getOverrides();
+  protected function loadOverrides(array $names) {
+    $overrides = array();
+    foreach ($this->getSortedConfigFactoryOverrides() as $override) {
+      // Existing overrides take precedence since these will have been added
+      // by events with a higher priority.
+      $overrides = NestedArray::mergeDeepArray(array($override->loadOverrides($names), $overrides), TRUE);
+    }
+    return $overrides;
   }
 
   /**
@@ -268,11 +248,14 @@ public function rename($old_name, $new_name) {
    * {@inheritdoc}
    */
   public function getCacheKey($name) {
-    $can_override = $this->canOverride($name);
-    $cache_key = $name . ':' . ($can_override ? 'overrides' : 'raw');
-
-    if ($can_override && isset($this->language)) {
-      $cache_key =  $cache_key . ':' . $this->language->id;
+    if ($this->useOverrides) {
+      $cache_key = $name . ':overrides';
+      foreach($this->getSortedConfigFactoryOverrides() as $override) {
+        $cache_key =  $cache_key . ':' . $override->getCacheSuffix();
+      }
+    }
+    else {
+      $cache_key = $name . ':raw';
     }
     return $cache_key;
   }
@@ -298,74 +281,11 @@ public function clearStaticCache() {
   /**
    * {@inheritdoc}
    */
-  public function setLanguage(Language $language = NULL) {
-    $this->language = $language;
-    return $this;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function setLanguageFromDefault(LanguageDefault $language_default) {
-    $this->language = $language_default->get();
-    return $this;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getLanguage() {
-    return $this->language;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public 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;
-        }
-      }
-    }
-    return $language_names;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getLanguageConfigName($langcode, $name) {
-    if (strpos($name, static::LANGUAGE_CONFIG_PREFIX) === 0) {
-      return FALSE;
-    }
-    return static::LANGUAGE_CONFIG_PREFIX . '.' . $langcode . '.' . $name;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
   public function listAll($prefix = '') {
     return $this->storage->listAll($prefix);
   }
 
   /**
-   * Determines if a particular configuration object can be overridden.
-   *
-   * Language override configuration should not be overridden.
-   *
-   * @param string $name
-   *   The name of the configuration object.
-   *
-   * @return bool
-   *   TRUE if the configuration object can be overridden.
-   */
-  protected function canOverride($name) {
-    return $this->useOverrides && !(strpos($name, static::LANGUAGE_CONFIG_PREFIX) === 0);
-  }
-
-  /**
    * Removes stale static cache entries when configuration is saved.
    *
    * @param ConfigCrudEvent $event
@@ -392,4 +312,30 @@ static function getSubscribedEvents() {
     return $events;
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public function addOverride(ConfigFactoryOverrideInterface $config_factory_override, $priority) {
+    $this->configFactoryOverrides[$priority][] = $config_factory_override;
+    // Force the overrides to be re-sorted.
+    $this->sortedConfigFactoryOverrides = NULL;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getSortedConfigFactoryOverrides() {
+    if (!isset($this->sortedConfigFactoryOverrides)) {
+      // Sort the override objects according to priority.
+      krsort($this->configFactoryOverrides);
+      // Merge nested override objects from $this->configFactoryOverrides into
+      // $this->sortedConfigFactoryOverrides.
+      $this->sortedConfigFactoryOverrides = array();
+      foreach ($this->configFactoryOverrides as $overrides) {
+        $this->sortedConfigFactoryOverrides = array_merge($this->sortedConfigFactoryOverrides, $overrides);
+      }
+    }
+    return $this->sortedConfigFactoryOverrides;
+  }
+
 }
diff --git a/core/lib/Drupal/Core/Config/ConfigFactoryInterface.php b/core/lib/Drupal/Core/Config/ConfigFactoryInterface.php
index 1969e82..ea60d67 100644
--- a/core/lib/Drupal/Core/Config/ConfigFactoryInterface.php
+++ b/core/lib/Drupal/Core/Config/ConfigFactoryInterface.php
@@ -7,20 +7,12 @@
 
 namespace Drupal\Core\Config;
 
-use Drupal\Core\Language\Language;
-use Drupal\Core\Language\LanguageDefault;
-
 /**
  * Defines the interface for a configuration object factory.
  */
 interface ConfigFactoryInterface {
 
   /**
-   * Prefix for all language configuration files.
-   */
-  const LANGUAGE_CONFIG_PREFIX = 'language.config';
-
-  /**
    * Sets the override state.
    *
    * @param bool $state
@@ -117,78 +109,35 @@ public function getCacheKeys($name);
   public function clearStaticCache();
 
   /**
-   * Sets the language to be used in configuration overrides.
-   *
-   * @param \Drupal\Core\Language\Language $language
-   *   The language object to be set on the config factory. Used to override
-   *   configuration by language.
-   *
-   * @return $this
-   */
-  public function setLanguage(Language $language = NULL);
-
-  /**
-   * Sets the language for configuration overrides using the default language.
-   *
-   * @param \Drupal\Core\Language\LanguageDefault $language_default
-   *   The default language service. This sets the initial language on the
-   *   config factory to the site's default. The language can be used to
-   *   override configuration data if language overrides are available.
-   *
-   * @return $this
-   */
-  public function setLanguageFromDefault(LanguageDefault $language_default);
-
-  /**
-   * Gets the language Used to override configuration.
-   *
-   * @return \Drupal\Core\Language\Language
-   */
-  public function getLanguage();
-
-  /**
-   * Gets configuration names for this language.
+   * Gets configuration object names starting with a given prefix.
    *
-   * It will be the same name with a prefix depending on language code:
-   * language.config.LANGCODE.NAME
+   * @see \Drupal\Core\Config\StorageInterface::listAll()
    *
-   * @param array $names
-   *   A list of configuration object names.
+   * @param string $prefix
+   *   (optional) The prefix to search for. If omitted, all configuration object
+   *   names that exist are returned.
    *
    * @return array
-   *   The localized config names, keyed by configuration object name.
+   *   An array containing matching configuration object names.
    */
-  public function getLanguageConfigNames(array $names);
+  public function listAll($prefix = '');
 
   /**
-   * Gets configuration name for the provided language.
-   *
-   * The name will be the same name with a prefix depending on language code:
-   * language.config.LANGCODE.NAME
-   *
-   * @param string $langcode
-   *   The language code.
-   * @param string $name
-   *   The name of the configuration object.
+   * Adds config factory override service.
    *
-   * @return bool|string
-   *   The configuration name for configuration object providing overrides.
-   *   Returns false if the name already starts with the language config prefix.
+   * @param \Drupal\Core\Config\ConfigFactoryOverrideInterface $config_factory_override
+   *   The config factory to add.
+   * @param int $priority
+   *   Priority of the config factory override.
    */
-  public function getLanguageConfigName($langcode, $name);
+  public function addOverride(ConfigFactoryOverrideInterface $config_factory_override, $priority);
 
   /**
-   * Gets configuration object names starting with a given prefix.
-   *
-   * @see \Drupal\Core\Config\StorageInterface::listAll()
-   *
-   * @param string $prefix
-   *   (optional) The prefix to search for. If omitted, all configuration object
-   *   names that exist are returned.
+   * Returns the sorted array of config factory override objects.
    *
-   * @return array
-   *   An array containing matching configuration object names.
+   * @return array|\Drupal\Core\Config\ConfigFactoryOverrideInterface[]
+   *   An array of config factory override objects.
    */
-  public function listAll($prefix = '');
+  public function getSortedConfigFactoryOverrides();
 
 }
diff --git a/core/lib/Drupal/Core/Config/ConfigFactoryOverrideInterface.php b/core/lib/Drupal/Core/Config/ConfigFactoryOverrideInterface.php
new file mode 100644
index 0000000..75298b3
--- /dev/null
+++ b/core/lib/Drupal/Core/Config/ConfigFactoryOverrideInterface.php
@@ -0,0 +1,52 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\Config\ConfigFactoryOverrideInterface.
+ */
+
+namespace Drupal\Core\Config;
+
+/**
+ * Defines the interface for a configuration factory override object.
+ */
+interface ConfigFactoryOverrideInterface {
+
+  /**
+   * @param array $names
+   *   A list of configuration names that is being loaded.
+   *
+   * @return array
+   *   An array keyed by configuration name of override data.
+   */
+  public function loadOverrides($names);
+
+  /**
+   * The string to append to the configuration static cache.
+   *
+   * @return string
+   *   A string to append to the configuration static cache.
+   */
+  public function getCacheSuffix();
+
+  /**
+   * Reacts to default configuration installation during extension install.
+   *
+   * @param string $type
+   *   The type of extension being installed. Either 'module' or 'theme'.
+   * @param string $name
+   *   The name of the extension.
+   */
+  public function install($type, $name);
+
+  /**
+   * Reacts to configuration removal during extension uninstallation.
+   *
+   * @param string $type
+   *   The type of extension being uninstalled. Either 'module' or 'theme'.
+   * @param string $name
+   *   The name of the extension.
+   */
+  public function uninstall($type, $name);
+
+}
diff --git a/core/lib/Drupal/Core/Config/ConfigFactoryOverridePass.php b/core/lib/Drupal/Core/Config/ConfigFactoryOverridePass.php
new file mode 100644
index 0000000..beae669
--- /dev/null
+++ b/core/lib/Drupal/Core/Config/ConfigFactoryOverridePass.php
@@ -0,0 +1,33 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\Config\ConfigFactoryOverridePass.
+ */
+
+namespace Drupal\Core\Config;
+
+use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
+use Symfony\Component\DependencyInjection\ContainerBuilder;
+use Symfony\Component\DependencyInjection\Reference;
+
+/**
+ * Adds services to the config factory service.
+ *
+ * @see \Drupal\Core\Config\ConfigFactory
+ * @see \Drupal\Core\Config\ConfigFactoryOverrideInterface
+ */
+class ConfigFactoryOverridePass implements CompilerPassInterface {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function process(ContainerBuilder $container) {
+    $manager = $container->getDefinition('config.factory');
+    foreach ($container->findTaggedServiceIds('config.factory.override') as $id => $attributes) {
+      $priority = isset($attributes[0]['priority']) ? $attributes[0]['priority'] : 0;
+      $manager->addMethodCall('addOverride', array(new Reference($id), $priority));
+    }
+  }
+
+}
diff --git a/core/lib/Drupal/Core/Config/ConfigImporter.php b/core/lib/Drupal/Core/Config/ConfigImporter.php
index b91964e..27602a3 100644
--- a/core/lib/Drupal/Core/Config/ConfigImporter.php
+++ b/core/lib/Drupal/Core/Config/ConfigImporter.php
@@ -264,7 +264,7 @@ protected function process($op, $name) {
    *   The name of the configuration to process.
    */
   protected function importConfig($op, $name) {
-    $config = new Config($name, $this->storageComparer->getTargetStorage(), $this->eventDispatcher, $this->typedConfigManager);
+    $config = new Config($name, $this->storageComparer->getTargetStorage(), $this->typedConfigManager, $this->eventDispatcher);
     if ($op == 'delete') {
       $config->delete();
     }
@@ -301,13 +301,13 @@ protected function importInvokeOwner($op, $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);
+      $old_config = new Config($name, $this->storageComparer->getTargetStorage(), $this->typedConfigManager, $this->eventDispatcher);
       if ($old_data = $this->storageComparer->getTargetStorage()->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);
+      $new_config = new Config($name, $this->storageComparer->getTargetStorage(), $this->typedConfigManager, $this->eventDispatcher);
       if ($data !== FALSE) {
         $new_config->setData($data);
       }
diff --git a/core/lib/Drupal/Core/Config/ConfigInstaller.php b/core/lib/Drupal/Core/Config/ConfigInstaller.php
index 2bb06b3..5c87238 100644
--- a/core/lib/Drupal/Core/Config/ConfigInstaller.php
+++ b/core/lib/Drupal/Core/Config/ConfigInstaller.php
@@ -107,18 +107,18 @@ public function installDefaultConfig($type, $name) {
     if (!empty($config_to_install)) {
       $old_state = $this->configFactory->getOverrideState();
       $this->configFactory->setOverrideState(FALSE);
-      foreach ($config_to_install as $name) {
+      foreach ($config_to_install as $config_name) {
         // Only import new config.
-        if ($this->activeStorage->exists($name)) {
+        if ($this->activeStorage->exists($config_name)) {
           continue;
         }
 
-        $new_config = new Config($name, $this->activeStorage, $this->eventDispatcher, $this->typedConfig);
-        $data = $source_storage->read($name);
+        $new_config = new Config($config_name, $this->activeStorage, $this->typedConfig, $this->eventDispatcher);
+        $data = $source_storage->read($config_name);
         if ($data !== FALSE) {
           $new_config->setData($data);
         }
-        if ($entity_type = $this->configManager->getEntityTypeIdByName($name)) {
+        if ($entity_type = $this->configManager->getEntityTypeIdByName($config_name)) {
           $this->configManager
             ->getEntityManager()
             ->getStorageController($entity_type)
@@ -131,6 +131,11 @@ public function installDefaultConfig($type, $name) {
       }
       $this->configFactory->setOverrideState($old_state);
     }
+
+    // Allow configFactory overrides to respond to installation.
+    foreach ($this->configFactory->getSortedConfigFactoryOverrides() as $config_override) {
+      $config_override->install($type, $name);
+    }
   }
 
 }
diff --git a/core/lib/Drupal/Core/Config/ConfigManager.php b/core/lib/Drupal/Core/Config/ConfigManager.php
index 65a7846..415b105 100644
--- a/core/lib/Drupal/Core/Config/ConfigManager.php
+++ b/core/lib/Drupal/Core/Config/ConfigManager.php
@@ -128,6 +128,11 @@ function uninstall($type, $name) {
     foreach ($config_names as $config_name) {
       $this->configFactory->get($config_name)->delete();
     }
+    // Allow configFactory overrides to respond to uninstallation.
+    foreach ($this->configFactory->getSortedConfigFactoryOverrides() as $config_override) {
+      $config_override->uninstall($type, $name);
+    }
+
     $schema_dir = drupal_get_path($type, $name) . '/config/schema';
     if (is_dir($schema_dir)) {
       // Refresh the schema cache if uninstalling an extension that provides
diff --git a/core/lib/Drupal/Core/Config/FileStorage.php b/core/lib/Drupal/Core/Config/FileStorage.php
index 2df9fbd..b139374 100644
--- a/core/lib/Drupal/Core/Config/FileStorage.php
+++ b/core/lib/Drupal/Core/Config/FileStorage.php
@@ -241,4 +241,15 @@ public function deleteAll($prefix = '') {
 
     return $success;
   }
+
+  /**
+   * Sets the filesystem path for configuration objects.
+   *
+   * @param string $directory
+   *   The filesystem path for configuration objects.
+   */
+  public function setDirectory($directory) {
+    $this->directory = $directory;
+  }
+
 }
diff --git a/core/lib/Drupal/Core/CoreServiceProvider.php b/core/lib/Drupal/Core/CoreServiceProvider.php
index d99ae28..571e4a4 100644
--- a/core/lib/Drupal/Core/CoreServiceProvider.php
+++ b/core/lib/Drupal/Core/CoreServiceProvider.php
@@ -8,6 +8,7 @@
 namespace Drupal\Core;
 
 use Drupal\Core\Cache\ListCacheBinsPass;
+use Drupal\Core\Config\ConfigFactoryOverridePass;
 use Drupal\Core\DependencyInjection\ServiceProviderInterface;
 use Drupal\Core\DependencyInjection\ContainerBuilder;
 use Drupal\Core\DependencyInjection\Compiler\ModifyServiceDefinitionsPass;
@@ -75,6 +76,9 @@ public function register(ContainerBuilder $container) {
     // Add the compiler pass that will process the tagged theme negotiator
     // service.
     $container->addCompilerPass(new ThemeNegotiatorPass());
+    // Add the compiler pass that will process the tagged config factory
+    // override services.
+    $container->addCompilerPass(new ConfigFactoryOverridePass());
     // Add the compiler pass that lets service providers modify existing
     // service definitions.
     $container->addCompilerPass(new ModifyServiceDefinitionsPass());
diff --git a/core/lib/Drupal/Core/Datetime/Date.php b/core/lib/Drupal/Core/Datetime/Date.php
index 5c2b92b..c908ca8 100644
--- a/core/lib/Drupal/Core/Datetime/Date.php
+++ b/core/lib/Drupal/Core/Datetime/Date.php
@@ -215,11 +215,10 @@ protected function t($string, array $args = array(), array $options = array()) {
    */
   protected function dateFormat($format, $langcode) {
     if (!isset($this->dateFormats[$format][$langcode])) {
-      // Enter a language specific context so the right date format is loaded.
-      $original_language = $this->configFactory->getLanguage();
-      $this->configFactory->setLanguage(new Language(array('id' => $langcode)));
+      $original_language = $this->languageManager->getConfigOverrideLanguage();
+      $this->languageManager->setConfigOverrideLanguage(new Language(array('id' => $langcode)));
       $this->dateFormats[$format][$langcode] = $this->dateFormatStorage->load($format);
-      $this->configFactory->setLanguage($original_language);
+      $this->languageManager->setConfigOverrideLanguage($original_language);
     }
     return $this->dateFormats[$format][$langcode];
   }
diff --git a/core/lib/Drupal/Core/Language/LanguageManager.php b/core/lib/Drupal/Core/Language/LanguageManager.php
index 6ddf673..783ec20 100644
--- a/core/lib/Drupal/Core/Language/LanguageManager.php
+++ b/core/lib/Drupal/Core/Language/LanguageManager.php
@@ -329,4 +329,24 @@ public static function getStandardLanguageList() {
     );
   }
 
+  /**
+   * {@inheritdoc}
+   *
+   * This function is a noop since the configuration can not be overridden by
+   * language unless the Language module is enabled. This replaces the default
+   * language manger with a configurable language manager.
+   *
+   * @see \Drupal\language\ConfigurableLanguageManager::setConfigOverrideLanguage()
+   */
+  public function setConfigOverrideLanguage(Language $language) {
+    return $this;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getConfigOverrideLanguage() {
+    return $this->getCurrentLanguage();
+  }
+
 }
diff --git a/core/lib/Drupal/Core/Language/LanguageManagerInterface.php b/core/lib/Drupal/Core/Language/LanguageManagerInterface.php
index 16c7c01..764cf0b 100644
--- a/core/lib/Drupal/Core/Language/LanguageManagerInterface.php
+++ b/core/lib/Drupal/Core/Language/LanguageManagerInterface.php
@@ -168,4 +168,23 @@ public function getFallbackCandidates($langcode = NULL, array $context = array()
    */
   function getLanguageSwitchLinks($type, $path);
 
+  /**
+   * Sets the configuration override language.
+   *
+   * @param \Drupal\Core\Language\Language $language
+   *   The language to override configuration with.
+   *
+   * @return $this
+   *   The language manager.
+   */
+  public function setConfigOverrideLanguage(Language $language);
+
+  /**
+   * Gets the current configuration override language.
+   *
+   * @return \Drupal\Core\Language\Language $language
+   *   The current configuration override language.
+   */
+  public function getConfigOverrideLanguage();
+
 }
diff --git a/core/modules/ckeditor/lib/Drupal/ckeditor/Tests/CKEditorTest.php b/core/modules/ckeditor/lib/Drupal/ckeditor/Tests/CKEditorTest.php
index 4f59069..3653f26 100644
--- a/core/modules/ckeditor/lib/Drupal/ckeditor/Tests/CKEditorTest.php
+++ b/core/modules/ckeditor/lib/Drupal/ckeditor/Tests/CKEditorTest.php
@@ -336,7 +336,7 @@ function testLanguages() {
    * Tests that CKEditor plugins participate in JS translation.
    */
   function testJSTranslation() {
-    $this->enableModules(array('locale'));
+    $this->enableModules(array('language', 'locale'));
     $this->installSchema('locale', 'locales_source');
     $this->installSchema('locale', 'locales_location');
     $editor = entity_load('editor', 'filtered_html');
diff --git a/core/modules/config/lib/Drupal/config/Tests/ConfigEventsTest.php b/core/modules/config/lib/Drupal/config/Tests/ConfigEventsTest.php
index 27e8845..48c8727 100644
--- a/core/modules/config/lib/Drupal/config/Tests/ConfigEventsTest.php
+++ b/core/modules/config/lib/Drupal/config/Tests/ConfigEventsTest.php
@@ -37,7 +37,7 @@ public static function getInfo() {
   function testConfigEvents() {
     $name = 'config_events_test.test';
 
-    $config = new Config($name, \Drupal::service('config.storage'), \Drupal::service('event_dispatcher'), \Drupal::service('config.typed'));
+    $config = new Config($name, \Drupal::service('config.storage'), \Drupal::service('config.typed'), \Drupal::service('event_dispatcher'));
     $config->set('key', 'initial');
     \Drupal::state()->get('config_events_test.event', FALSE);
     $this->assertIdentical(\Drupal::state()->get('config_events_test.event', array()), array(), 'No events fired by creating a new configuration object');
diff --git a/core/modules/config/lib/Drupal/config/Tests/ConfigLanguageOverride.php b/core/modules/config/lib/Drupal/config/Tests/ConfigLanguageOverrideTest.php
similarity index 60%
rename from core/modules/config/lib/Drupal/config/Tests/ConfigLanguageOverride.php
rename to core/modules/config/lib/Drupal/config/Tests/ConfigLanguageOverrideTest.php
index 12ff3cd..9d2655a 100644
--- a/core/modules/config/lib/Drupal/config/Tests/ConfigLanguageOverride.php
+++ b/core/modules/config/lib/Drupal/config/Tests/ConfigLanguageOverrideTest.php
@@ -2,7 +2,7 @@
 
 /**
  * @file
- * Contains \Drupal\config\Tests\ConfigLanguageOverride.
+ * Contains \Drupal\config\Tests\ConfigLanguageOverrideTest.
  */
 
 namespace Drupal\config\Tests;
@@ -13,14 +13,14 @@
 /**
  * Tests language config override.
  */
-class ConfigLanguageOverride extends DrupalUnitTestBase {
+class ConfigLanguageOverrideTest extends DrupalUnitTestBase {
 
   /**
    * Modules to enable.
    *
    * @var array
    */
-  public static $modules = array('config_test', 'user', 'language', 'system', 'field');
+  public static $modules = array('user', 'language', 'config_test',  'system', 'field');
 
   public static function getInfo() {
     return array(
@@ -39,16 +39,10 @@ public function setUp() {
    * Tests locale override based on language.
    */
   function testConfigLanguageOverride() {
-    // The default configuration factory does not have the default language
-    // injected unless the Language module is enabled.
-    $config = \Drupal::config('config_test.system');
-    $this->assertIdentical($config->get('foo'), 'bar');
-
-    // \Drupal\language\LanguageServiceProvider::alter() calls
-    // \Drupal\Core\Config\ConfigFactory::setLanguageFromDefault() to set the
-    // language when the Language module is enabled. This test ensures that
+    // The language module implements a config factory override object that
+    // overrides configuration when the Language module is enabled. This test ensures that
     // English overrides work.
-    \Drupal::configFactory()->setLanguageFromDefault(\Drupal::service('language.default'));
+    \Drupal::languageManager()->setConfigOverrideLanguage(language_load('en'));
     $config = \Drupal::config('config_test.system');
     $this->assertIdentical($config->get('foo'), 'en bar');
 
@@ -65,20 +59,20 @@ function testConfigLanguageOverride() {
       'id' => 'de',
     )));
 
-    \Drupal::configFactory()->setLanguage(language_load('fr'));
+    \Drupal::languageManager()->setConfigOverrideLanguage(language_load('fr'));
     $config = \Drupal::config('config_test.system');
     $this->assertIdentical($config->get('foo'), 'fr bar');
 
-    \Drupal::configFactory()->setLanguage(language_load('de'));
+    \Drupal::languageManager()->setConfigOverrideLanguage(language_load('de'));
     $config = \Drupal::config('config_test.system');
     $this->assertIdentical($config->get('foo'), 'de bar');
 
     // Test overrides of completely new configuration objects. In normal runtime
     // this should only happen for configuration entities as we should not be
     // creating simple configuration objects on the fly.
-    $language_config_name = \Drupal::configFactory()->getLanguageConfigName('de', 'config_test.new');
-    \Drupal::config($language_config_name)->set('language', 'override')->save();
-    \Drupal::config('config_test.new');
+    \Drupal::languageManager()
+      ->config('config_test.new', language_load('de'))
+      ->set('language', 'override')->save();
     $config = \Drupal::config('config_test.new');
     $this->assertTrue($config->isNew(), 'The configuration object config_test.new is new');
     $this->assertIdentical($config->get('language'), 'override');
@@ -87,11 +81,6 @@ function testConfigLanguageOverride() {
     $config = \Drupal::config('config_test.new');
     $this->assertIdentical($config->get('language'), NULL);
     \Drupal::configFactory()->setOverrideState($old_state);
-
-    // Ensure that language configuration overrides can not be overridden.
-    global $conf;
-    $conf[$language_config_name]['language'] = 'conf cannot override';
-    $this->assertIdentical(\Drupal::config($language_config_name)->get('language'), 'override');
   }
 }
 
diff --git a/core/modules/config/lib/Drupal/config/Tests/ConfigLanguageOverrideWebTest.php b/core/modules/config/lib/Drupal/config/Tests/ConfigLanguageOverrideWebTest.php
index 3ffb54f..01cda65 100644
--- a/core/modules/config/lib/Drupal/config/Tests/ConfigLanguageOverrideWebTest.php
+++ b/core/modules/config/lib/Drupal/config/Tests/ConfigLanguageOverrideWebTest.php
@@ -45,10 +45,13 @@ function testSiteNameTranslation() {
       'direction' => '0',
     );
     $this->drupalPostForm('admin/config/regional/language/add', $edit, t('Add custom language'));
-
+    \Drupal::languageManager()->reset();
     // Save an override for the XX language.
-    $config_name = \Drupal::configFactory()->getLanguageConfigName('xx', 'system.site');
-    \Drupal::config($config_name)->set('name', 'XX site name')->save();
+    $language = language_load('xx');
+    \Drupal::languageManager()
+      ->config('system.site', $language)
+      ->set('name', 'XX site name')
+      ->save();
 
     $this->drupalLogout();
 
diff --git a/core/modules/config/lib/Drupal/config/Tests/ConfigOverridesPriorityTest.php b/core/modules/config/lib/Drupal/config/Tests/ConfigOverridesPriorityTest.php
index 49482f9..112eeb3 100644
--- a/core/modules/config/lib/Drupal/config/Tests/ConfigOverridesPriorityTest.php
+++ b/core/modules/config/lib/Drupal/config/Tests/ConfigOverridesPriorityTest.php
@@ -15,7 +15,7 @@
  */
 class ConfigOverridesPriorityTest extends DrupalUnitTestBase {
 
-  public static $modules = array('system', 'config', 'config_override');
+  public static $modules = array('system', 'config', 'config_override', 'language');
 
   public static function getInfo() {
     return array(
@@ -59,10 +59,9 @@ public function testOverridePriorities() {
       'name' => 'French',
       'id' => 'fr',
     ));
-    $config_factory->setLanguage($language);
-    $language_config_name = $config_factory->getLanguageConfigName($language->id, 'system.site');
-    $config_factory
-      ->get($language_config_name)
+    \Drupal::languageManager()->setConfigOverrideLanguage($language);
+    \Drupal::languageManager()
+      ->config('system.site', $language)
       ->set('name', $language_overridden_name)
       ->set('mail', $language_overridden_mail)
       ->save();
diff --git a/core/modules/config/lib/Drupal/config/Tests/ConfigSchemaTest.php b/core/modules/config/lib/Drupal/config/Tests/ConfigSchemaTest.php
index 62341ee..aed67af 100644
--- a/core/modules/config/lib/Drupal/config/Tests/ConfigSchemaTest.php
+++ b/core/modules/config/lib/Drupal/config/Tests/ConfigSchemaTest.php
@@ -21,7 +21,7 @@ class ConfigSchemaTest extends DrupalUnitTestBase {
    *
    * @var array
    */
-  public static $modules = array('system', 'locale', 'field', 'image', 'config_test');
+  public static $modules = array('system', 'language', ',locale', 'field', 'image', 'config_test');
 
   public static function getInfo() {
     return array(
diff --git a/core/modules/config/lib/Drupal/config/Tests/DefaultConfigTest.php b/core/modules/config/lib/Drupal/config/Tests/DefaultConfigTest.php
index b7424f3..8c0f9cd 100644
--- a/core/modules/config/lib/Drupal/config/Tests/DefaultConfigTest.php
+++ b/core/modules/config/lib/Drupal/config/Tests/DefaultConfigTest.php
@@ -79,9 +79,8 @@ 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).
+      if (strpos($config_name, 'migrate.migration') === 0) {
         continue;
       }
 
diff --git a/core/modules/config/tests/config_override/config_override.services.yml b/core/modules/config/tests/config_override/config_override.services.yml
index 586ce49..5272a84 100644
--- a/core/modules/config/tests/config_override/config_override.services.yml
+++ b/core/modules/config/tests/config_override/config_override.services.yml
@@ -1,9 +1,9 @@
 services:
-  config_override_config_subscriber:
-    class: Drupal\config_override\EventSubscriber\ConfigModuleOverrideSubscriber
+  config_override.overrider:
+    class: Drupal\config_override\ConfigOverrider
     tags:
-      - { name: event_subscriber }
-  config_override_low_priority_config_subscriber:
-    class: Drupal\config_override\EventSubscriber\ConfigModuleLowPriorityOverrideSubscriber
+      - { name: config.factory.override}
+  config_override.low_priority_overrider:
+    class: Drupal\config_override\ConfigOverriderLowPriority
     tags:
-      - { name: event_subscriber }
+      - { name: config.factory.override, priority: -100 }
diff --git a/core/modules/config/tests/config_override/lib/Drupal/config_override/ConfigOverrider.php b/core/modules/config/tests/config_override/lib/Drupal/config_override/ConfigOverrider.php
new file mode 100644
index 0000000..d82ed2e
--- /dev/null
+++ b/core/modules/config/tests/config_override/lib/Drupal/config_override/ConfigOverrider.php
@@ -0,0 +1,56 @@
+<?Php
+
+/**
+ * @file
+ * Contains \Drupal\config_override\EventSubscriber\ConfigModuleOverrideSubscriber.
+ */
+
+namespace Drupal\config_override;
+
+use Drupal\Core\Config\ConfigEvents;
+use Drupal\Core\Config\ConfigFactoryOverrideInterface;
+use Drupal\Core\Config\ConfigModuleOverridesEvent;
+use Symfony\Component\EventDispatcher\EventSubscriberInterface;
+
+/**
+ * Tests module overrides for configuration.
+ */
+class ConfigOverrider implements ConfigFactoryOverrideInterface {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function loadOverrides($names) {
+    $overrides = array();
+    if (!empty($GLOBALS['config_test_run_module_overrides'])) {
+      if (in_array('system.site', $names)) {
+        $overrides = $overrides + array('system.site' => array('name' => 'ZOMG overridden site name'));
+      }
+      if (in_array('config_override.new', $names)) {
+        $overrides = $overrides + array('config_override.new' => array('module' => 'override'));
+      }
+    }
+    return $overrides;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getCacheSuffix() {
+    return 'ConfigOverrider';
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function install($type, $name) {
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function uninstall($type, $name) {
+  }
+
+}
+
diff --git a/core/modules/config/tests/config_override/lib/Drupal/config_override/ConfigOverriderLowPriority.php b/core/modules/config/tests/config_override/lib/Drupal/config_override/ConfigOverriderLowPriority.php
new file mode 100644
index 0000000..53a30e7
--- /dev/null
+++ b/core/modules/config/tests/config_override/lib/Drupal/config_override/ConfigOverriderLowPriority.php
@@ -0,0 +1,57 @@
+<?Php
+
+/**
+ * @file
+ * Contains \Drupal\config_override\EventSubscriber\ConfigModuleLowPriorityOverrideSubscriber.
+ */
+
+namespace Drupal\config_override;
+
+use Drupal\Core\Config\ConfigFactoryOverrideInterface;
+
+/**
+ * Tests module overrides for configuration.
+ */
+class ConfigOverriderLowPriority implements ConfigFactoryOverrideInterface {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function loadOverrides($names) {
+    $overrides = array();
+    if (!empty($GLOBALS['config_test_run_module_overrides'])) {
+      if (in_array('system.site', $names)) {
+        $overrides = array('system.site' =>
+          array(
+            // This override should apply because it is not overridden by the
+            // higher priority listener.
+            'name' => 'Should not apply because of higher priority listener',
+            'slogan' => 'Yay for overrides!',
+          )
+        );
+      }
+    }
+    return $overrides;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getCacheSuffix() {
+    return 'ConfigOverriderLowPriority';
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function install($type, $name) {
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function uninstall($type, $name) {
+  }
+
+}
+
diff --git a/core/modules/config/tests/config_override/lib/Drupal/config_override/EventSubscriber/ConfigModuleLowPriorityOverrideSubscriber.php b/core/modules/config/tests/config_override/lib/Drupal/config_override/EventSubscriber/ConfigModuleLowPriorityOverrideSubscriber.php
deleted file mode 100644
index fd7e26c..0000000
--- a/core/modules/config/tests/config_override/lib/Drupal/config_override/EventSubscriber/ConfigModuleLowPriorityOverrideSubscriber.php
+++ /dev/null
@@ -1,44 +0,0 @@
-<?Php
-
-/**
- * @file
- * Contains \Drupal\config_override\EventSubscriber\ConfigModuleLowPriorityOverrideSubscriber.
- */
-
-namespace Drupal\config_override\EventSubscriber;
-
-use Drupal\Core\Config\ConfigEvents;
-use Drupal\Core\Config\ConfigModuleOverridesEvent;
-use Symfony\Component\EventDispatcher\EventSubscriberInterface;
-
-/**
- * Tests module overrides for configuration.
- */
-class ConfigModuleLowPriorityOverrideSubscriber implements EventSubscriberInterface {
-
-  public function onConfigModuleOverride(ConfigModuleOverridesEvent $event) {
-    if (!empty($GLOBALS['config_test_run_module_overrides'])) {
-      $names = $event->getNames();
-      if (in_array('system.site', $names)) {
-        $event->setOverride('system.site', array(
-          'name' => 'Should not apply because of higher priority listener',
-          // This override should apply because it is not overridden by the
-          // higher priority listener.
-          'slogan' => 'Yay for overrides!',
-        ));
-      }
-    }
-  }
-
-  /**
-   * Registers the methods in this class that should be listeners.
-   *
-   * @return array
-   *   An array of event listener definitions.
-   */
-  static function getSubscribedEvents() {
-    $events[ConfigEvents::MODULE_OVERRIDES][] = array('onConfigModuleOverride', 35);
-    return $events;
-  }
-}
-
diff --git a/core/modules/config/tests/config_override/lib/Drupal/config_override/EventSubscriber/ConfigModuleOverrideSubscriber.php b/core/modules/config/tests/config_override/lib/Drupal/config_override/EventSubscriber/ConfigModuleOverrideSubscriber.php
deleted file mode 100644
index e168111..0000000
--- a/core/modules/config/tests/config_override/lib/Drupal/config_override/EventSubscriber/ConfigModuleOverrideSubscriber.php
+++ /dev/null
@@ -1,42 +0,0 @@
-<?Php
-
-/**
- * @file
- * Contains \Drupal\config_override\EventSubscriber\ConfigModuleOverrideSubscriber.
- */
-
-namespace Drupal\config_override\EventSubscriber;
-
-use Drupal\Core\Config\ConfigEvents;
-use Drupal\Core\Config\ConfigModuleOverridesEvent;
-use Symfony\Component\EventDispatcher\EventSubscriberInterface;
-
-/**
- * Tests module overrides for configuration.
- */
-class ConfigModuleOverrideSubscriber implements EventSubscriberInterface {
-
-  public function onConfigModuleOverride(ConfigModuleOverridesEvent $event) {
-    if (!empty($GLOBALS['config_test_run_module_overrides'])) {
-      $names = $event->getNames();
-      if (in_array('system.site', $names)) {
-        $event->setOverride('system.site', array('name' => 'ZOMG overridden site name'));
-      }
-      if (in_array('config_override.new', $names)) {
-        $event->setOverride('config_override.new', array('module' => 'override'));
-      }
-    }
-  }
-
-  /**
-   * Registers the methods in this class that should be listeners.
-   *
-   * @return array
-   *   An array of event listener definitions.
-   */
-  static function getSubscribedEvents() {
-    $events[ConfigEvents::MODULE_OVERRIDES][] = array('onConfigModuleOverride', 40);
-    return $events;
-  }
-}
-
diff --git a/core/modules/config/tests/config_test/config/language.config.de.config_test.system.yml b/core/modules/config/tests/config_test/config/language/de/config_test.system.yml
similarity index 100%
rename from core/modules/config/tests/config_test/config/language.config.de.config_test.system.yml
rename to core/modules/config/tests/config_test/config/language/de/config_test.system.yml
diff --git a/core/modules/config/tests/config_test/config/language.config.en.config_test.system.yml b/core/modules/config/tests/config_test/config/language/en/config_test.system.yml
similarity index 100%
rename from core/modules/config/tests/config_test/config/language.config.en.config_test.system.yml
rename to core/modules/config/tests/config_test/config/language/en/config_test.system.yml
diff --git a/core/modules/config/tests/config_test/config/language.config.fr.config_test.system.yml b/core/modules/config/tests/config_test/config/language/fr/config_test.system.yml
similarity index 100%
rename from core/modules/config/tests/config_test/config/language.config.fr.config_test.system.yml
rename to core/modules/config/tests/config_test/config/language/fr/config_test.system.yml
diff --git a/core/modules/config_translation/lib/Drupal/config_translation/Form/ConfigTranslationDeleteForm.php b/core/modules/config_translation/lib/Drupal/config_translation/Form/ConfigTranslationDeleteForm.php
index 319e168..9a894d6 100644
--- a/core/modules/config_translation/lib/Drupal/config_translation/Form/ConfigTranslationDeleteForm.php
+++ b/core/modules/config_translation/lib/Drupal/config_translation/Form/ConfigTranslationDeleteForm.php
@@ -9,10 +9,9 @@
 
 use Drupal\config_translation\ConfigMapperManagerInterface;
 use Drupal\Core\Cache\Cache;
-use Drupal\Core\Config\StorageInterface;
-use Drupal\Core\Config\ConfigFactoryInterface;
 use Drupal\Core\Extension\ModuleHandlerInterface;
 use Drupal\Core\Form\ConfirmFormBase;
+use Drupal\language\Config\LanguageStorageInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 use Symfony\Component\HttpFoundation\Request;
 use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
@@ -23,9 +22,9 @@
 class ConfigTranslationDeleteForm extends ConfirmFormBase {
 
   /**
-   * The configuration storage.
+   * The language override configuration storage.
    *
-   * @var \Drupal\Core\Config\StorageInterface $config_storage
+   * @var \Drupal\language\Config\LanguageStorageInterface $config_storage
    */
   protected $configStorage;
 
@@ -60,20 +59,17 @@ class ConfigTranslationDeleteForm extends ConfirmFormBase {
   /**
    * Constructs a ConfigTranslationDeleteForm.
    *
-   * @param \Drupal\Core\Config\StorageInterface $config_storage
-   *   The configuration storage.
+   * @param \Drupal\language\Config\LanguageStorageInterface $config_storage
+   *   The language override configuration storage.
    * @param \Drupal\config_translation\ConfigMapperManagerInterface $config_mapper_manager
    *   The configuration mapper manager.
    * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
    *   The module handler.
-   * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
-   *   The configuration factory.
    */
-  public function __construct(StorageInterface $config_storage, ConfigMapperManagerInterface $config_mapper_manager, ModuleHandlerInterface $module_handler, ConfigFactoryInterface $config_factory) {
+  public function __construct(LanguageStorageInterface $config_storage, ConfigMapperManagerInterface $config_mapper_manager, ModuleHandlerInterface $module_handler) {
     $this->configStorage = $config_storage;
     $this->configMapperManager = $config_mapper_manager;
     $this->moduleHandler = $module_handler;
-    $this->configFactory = $config_factory;
   }
 
   /**
@@ -81,10 +77,9 @@ public function __construct(StorageInterface $config_storage, ConfigMapperManage
    */
   public static function create(ContainerInterface $container) {
     return new static(
-      $container->get('config.storage'),
+      $container->get('language.config_storage'),
       $container->get('plugin.manager.config_translation.mapper'),
-      $container->get('module_handler'),
-      $container->get('config.factory')
+      $container->get('module_handler')
     );
   }
 
@@ -141,9 +136,9 @@ public function buildForm(array $form, array &$form_state, Request $request = NU
    * {@inheritdoc}
    */
   public function submitForm(array &$form, array &$form_state) {
+    $this->configStorage->setLangcode($this->language->id);
     foreach ($this->mapper->getConfigNames() as $name) {
-      $config_name = $this->configFactory->getLanguageConfigName($this->language->id, $name);
-      $this->configStorage->delete($config_name);
+      $this->configStorage->delete($name);
     }
 
     // Flush all persistent caches.
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 22e6783..8726425 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
@@ -16,6 +16,7 @@
 use Drupal\Core\Form\BaseFormIdInterface;
 use Drupal\Core\Form\FormBase;
 use Drupal\Core\Language\Language;
+use Drupal\language\ConfigurableLanguageManagerInterface;
 use Drupal\locale\StringStorageInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 use Symfony\Component\HttpFoundation\Request;
@@ -62,6 +63,13 @@
   protected $mapper;
 
   /**
+   * The lanugage manager.
+   *
+   * @var \Drupal\language\ConfigurableLanguageManagerInterface
+   */
+  protected $languageManager;
+
+  /**
    * The language of the configuration translation.
    *
    * @var \Drupal\Core\Language\Language
@@ -96,12 +104,13 @@
    * @param \Drupal\Core\Config\ConfigFactoryInterface
    *   The config factory.
    */
-  public function __construct(TypedConfigManager $typed_config_manager, ConfigMapperManagerInterface $config_mapper_manager, StringStorageInterface $locale_storage, ModuleHandlerInterface $module_handler, ConfigFactoryInterface $config_factory) {
+  public function __construct(TypedConfigManager $typed_config_manager, ConfigMapperManagerInterface $config_mapper_manager, StringStorageInterface $locale_storage, ModuleHandlerInterface $module_handler, ConfigFactoryInterface $config_factory, ConfigurableLanguageManagerInterface $language_manager) {
     $this->typedConfigManager = $typed_config_manager;
     $this->configMapperManager = $config_mapper_manager;
     $this->localeStorage = $locale_storage;
     $this->moduleHandler = $module_handler;
     $this->configFactory = $config_factory;
+    $this->languageManager = $language_manager;
   }
 
   /**
@@ -113,7 +122,8 @@ public static function create(ContainerInterface $container) {
       $container->get('plugin.manager.config_translation.mapper'),
       $container->get('locale.storage'),
       $container->get('module_handler'),
-      $container->get('config.factory')
+      $container->get('config.factory'),
+      $container->get('language_manager')
     );
   }
 
@@ -172,8 +182,8 @@ public function buildForm(array $form, array &$form_state, Request $request = NU
     $this->configFactory->setOverrideState($old_state);
 
     // Set the translation target language on the configuration factory.
-    $original_language = $this->configFactory->getLanguage();
-    $this->configFactory->setLanguage($this->language);
+    $original_language = $this->languageManager->getConfigOverrideLanguage();
+    $this->languageManager->setConfigOverrideLanguage($this->language);
 
     // Add some information to the form state for easier form altering.
     $form_state['config_translation_mapper'] = $this->mapper;
@@ -199,7 +209,7 @@ public function buildForm(array $form, array &$form_state, Request $request = NU
     );
 
     // Set the configuration language back.
-    $this->configFactory->setLanguage($original_language);
+    $this->languageManager->setConfigOverrideLanguage($original_language);
 
     return $form;
   }
@@ -217,8 +227,7 @@ public function submitForm(array &$form, array &$form_state) {
     foreach ($this->mapper->getConfigNames() as $name) {
       // Set configuration values based on form submission and source values.
       $base_config = $this->config($name);
-      $translation_config_name = $this->configFactory->getLanguageConfigName($this->language->id, $name);
-      $translation_config = $this->config($translation_config_name);
+      $translation_config = $this->languageManager->config($name, $this->language);
       $locations = $this->localeStorage->getLocations(array('type' => 'configuration', 'name' => $name));
 
       $this->setConfig($this->language, $base_config, $translation_config, $form_values[$name], !empty($locations));
diff --git a/core/modules/config_translation/lib/Drupal/config_translation/Tests/ConfigTranslationUiTest.php b/core/modules/config_translation/lib/Drupal/config_translation/Tests/ConfigTranslationUiTest.php
index ed4b1e2..1997925 100644
--- a/core/modules/config_translation/lib/Drupal/config_translation/Tests/ConfigTranslationUiTest.php
+++ b/core/modules/config_translation/lib/Drupal/config_translation/Tests/ConfigTranslationUiTest.php
@@ -177,16 +177,14 @@ public function testSourceValueDuplicateSave() {
     $this->drupalPostForm("$translation_base_url/fr/add", $edit, t('Save translation'));
 
     // Read overridden file from active config.
-    $file_storage = new FileStorage($this->configDirectories[CONFIG_ACTIVE_DIRECTORY]);
-    $language_config_name = \Drupal::configFactory()->getLanguageConfigName('fr', 'system.site');
-    $config_parsed = $file_storage->read($language_config_name);
+    $config = \Drupal::languageManager()->config('system.site', language_load('fr'));
 
     // Expect both name and slogan in language specific file.
     $expected = array(
       'name' => 'FR ' . $site_name,
       'slogan' => 'FR ' . $site_slogan,
     );
-    $this->assertEqual($expected, $config_parsed);
+    $this->assertEqual($expected, $config->get());
 
     // Case 2: Update new value for site slogan and default value for site name.
     $this->drupalGet("$translation_base_url/fr/edit");
@@ -200,11 +198,11 @@ public function testSourceValueDuplicateSave() {
     );
     $this->drupalPostForm(NULL, $edit, t('Save translation'));
     $this->assertRaw(t('Successfully updated @language translation.', array('@language' => 'French')));
-    $config_parsed = $file_storage->read($language_config_name);
+    $config = \Drupal::languageManager()->config('system.site', language_load('fr'));
 
     // Expect only slogan in language specific file.
     $expected = array('slogan' => 'FR ' . $site_slogan);
-    $this->assertEqual($expected, $config_parsed);
+    $this->assertEqual($expected, $config->get());
 
     // Case 3: Keep default value for site name and slogan.
     $this->drupalGet("$translation_base_url/fr/edit");
@@ -214,10 +212,10 @@ public function testSourceValueDuplicateSave() {
       'config_names[system.site][slogan][translation]' => $site_slogan,
     );
     $this->drupalPostForm(NULL, $edit, t('Save translation'));
-    $config_parsed = $file_storage->read($language_config_name);
+    $config = \Drupal::languageManager()->config('system.site', language_load('fr'));
 
     // Expect no language specific file.
-    $this->assertFalse($config_parsed);
+    $this->assertTrue($config->isNew());
 
     // Check configuration page with translator user. Should have no access.
     $this->drupalLogout();
@@ -240,8 +238,6 @@ public function testSourceValueDuplicateSave() {
   public function testContactConfigEntityTranslation() {
     $this->drupalLogin($this->admin_user);
 
-    $file_storage = new FileStorage($this->configDirectories[CONFIG_ACTIVE_DIRECTORY]);
-
     $this->drupalGet('admin/structure/contact');
 
     // Check for default contact form configuration entity from Contact module.
@@ -285,13 +281,12 @@ public function testContactConfigEntityTranslation() {
       $this->drupalPostForm($translation_page_url, $edit, t('Save translation'));
 
       // Expect translated values in language specific file.
-      $language_config_name = \Drupal::configFactory()->getLanguageConfigName($langcode, 'contact.category.feedback');
-      $config_parsed = $file_storage->read($language_config_name);
+      $config = \Drupal::languageManager()->config('contact.category.feedback', language_load($langcode));
       $expected = array(
         'label' => 'Website feedback - ' . $langcode,
         'reply' => 'Thank you for your mail - ' . $langcode,
       );
-      $this->assertEqual($expected, $config_parsed);
+      $this->assertEqual($expected, $config->get());
 
       // Check for edit, delete links (and no 'add' link) for $langcode.
       $this->assertNoLinkByHref("$translation_base_url/$langcode/add");
@@ -349,9 +344,8 @@ public function testContactConfigEntityTranslation() {
       $this->assertNoLinkByHref("$translation_base_url/$langcode/delete");
 
       // Expect no language specific file present anymore.
-      $language_config_name = \Drupal::configFactory()->getLanguageConfigName($langcode, 'contact.category.feedback');
-      $config_parsed = $file_storage->read($language_config_name);
-      $this->assertFalse($config_parsed);
+      $config = \Drupal::languageManager()->config('contact.category.feedback', language_load($langcode));
+      $this->assertTrue($config->isNew());
     }
 
     // Check configuration page with translator user. Should have no access.
@@ -417,13 +411,12 @@ public function testDateFormatTranslation() {
       $this->drupalPostForm($translation_page_url, $edit, t('Save translation'));
 
       // Get translation and check we've got the right value.
-      $language_config_name = \Drupal::configFactory()->getLanguageConfigName('fr', 'system.date_format.' . $id);
-      $config_parsed = $file_storage->read($language_config_name);
+      $config = \Drupal::languageManager()->config('system.date_format.' . $id, language_load('fr'));
       $expected = array(
         'label' => $id . ' - FR',
         'pattern' => array('php' => 'D'),
       );
-      $this->assertEqual($expected, $config_parsed);
+      $this->assertEqual($expected, $config->get());
 
       // Formatting the date 8 / 27 / 1985 @ 13:37 EST with pattern D should
       // display "Tue".
diff --git a/core/modules/language/language.install b/core/modules/language/language.install
index 27541ca..c679999 100644
--- a/core/modules/language/language.install
+++ b/core/modules/language/language.install
@@ -6,6 +6,26 @@
  */
 
 /**
+ * Implements hook_install().
+ */
+function language_install() {
+  // Get all the existing modules that are enabled and install any language
+  // configuration.
+  $language_config_override = \Drupal::service('language.config_factory_override');
+  foreach (array_keys(\Drupal::moduleHandler()->getModuleList()) as $module) {
+    $language_config_override->install('module', $module);
+  }
+  /** @var \Drupal\Core\Extension\ThemeHandler $theme_handler */
+  $theme_handler = \Drupal::service('theme_handler');
+  foreach ($theme_handler->listInfo() as $theme) {
+    if ($theme->status) {
+      $language_config_override->install('theme', $theme->name);
+    }
+  }
+  \Drupal::configFactory()->reset();
+}
+
+/**
  * Implements hook_uninstall().
  */
 function language_uninstall() {
diff --git a/core/modules/language/language.services.yml b/core/modules/language/language.services.yml
index 422644a..95f9c97 100644
--- a/core/modules/language/language.services.yml
+++ b/core/modules/language/language.services.yml
@@ -11,3 +11,22 @@ services:
     class: Drupal\language\EventSubscriber\ConfigSubscriber
     tags:
       - { name: event_subscriber }
+  language.cache_config:
+    class: Drupal\Core\Cache\CacheBackendInterface
+    tags:
+      - { name: cache.bin }
+      - { name: persist }
+    factory_method: get
+    factory_service: cache_factory
+    arguments: [language_config]
+  language.config_storage:
+    class: Drupal\language\Config\LanguageStorage
+    arguments: ['@language.cache_config']
+    tags:
+      - { name: persist }
+  language.config_factory_override:
+    class: Drupal\language\Config\LanguageConfigOverride
+    arguments: ['@language.default', '@language.config_storage', '@config.typed']
+    tags:
+      - { name: config.factory.override, priority: -254 }
+      - { name: persist }
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..58b261e
--- /dev/null
+++ b/core/modules/language/lib/Drupal/language/Config/LanguageConfigOverride.php
@@ -0,0 +1,131 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\language\Config\LanguageConfigOverride.
+ */
+
+namespace Drupal\language\Config;
+
+use Drupal\Core\Config\FileStorage;
+use Drupal\Core\Config\Config;
+use Drupal\Core\Config\TypedConfigManagerInterface;
+use Drupal\Core\Language\Language;
+use Drupal\Core\Language\LanguageDefault;
+
+class LanguageConfigOverride implements LanguageConfigOverrideInterface {
+
+  /**
+   * The language configuration storage.
+   *
+   * @var \Drupal\language\Config\LanguageStorage
+   */
+  protected $storage;
+
+  /**
+   * The language object used to override configuration data.
+   *
+   * @var \Drupal\Core\Language\Language
+   */
+  protected $language;
+
+  /**
+   * Constructs the LanguageConfigOverride object.
+   *
+   * @param \Drupal\Core\Language\LanguageDefault $language_default
+   *   The default language service. This sets the initial language on the
+   *   config factory to the site's default. The language can be used to
+   *   override configuration data if language overrides are available.
+   * @param \Drupal\language\Config\LanguageStorageInterface $storage
+   *   The language configuration storage.
+   */
+  public function __construct(LanguageDefault $language_default, LanguageStorageInterface $storage, TypedConfigManagerInterface $typed_config) {
+    // Ensure that configuration can be localised if the site is monolingual
+    // but the Language module is enabled. This is the case for monolingual
+    // sites not in English.
+    $this->language = $language_default->get();
+    $this->storage = $storage->setLangcode($this->language->id);
+    $this->typedConfig = $typed_config;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function loadOverrides($names) {
+    return $this->storage->readMultiple($names);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getCacheSuffix() {
+    return $this->language->id;
+  }
+
+  /**
+   * {@inheritdoc}
+   *
+   * @todo maybe this should be done somewhere else?
+   */
+  public function install($type, $name) {
+    // Work out if this extension provides default language overrides.
+    $config_dir = drupal_get_path($type, $name) . '/config/language';
+    if (is_dir($config_dir)) {
+      // List all the directories.
+      // \DirectoryIterator on Windows requires an absolute path.
+      $it  = new \DirectoryIterator(realpath($config_dir));
+      foreach ($it as $dir) {
+        if (!$dir->isDot() && $dir->isDir() ) {
+          $default_language_config = new FileStorage($dir->getPathname());
+          $this->storage->setLangcode($dir->getFilename());
+          foreach ($default_language_config->listAll() as $config_name) {
+            $data = $default_language_config->read($config_name);
+            $config = new Config($config_name, $this->storage, $this->typedConfig);
+            $config->setData($data)->save();
+          }
+        }
+      }
+    }
+  }
+
+  /**
+   * {@inheritdoc}
+   *
+   * @todo maybe this should be done somewhere else?
+   */
+  public function uninstall($type, $name) {
+    // Can not use ConfigurableLanguageManager::getLanguages() since that would
+    // create a circular dependency.
+    $language_directory = config_get_config_directory() .'/language';
+    if (is_dir(($language_directory))) {
+      $it  = new \DirectoryIterator(realpath($language_directory));
+      foreach ($it as $dir) {
+        if (!$dir->isDot() && $dir->isDir() ) {
+          $this->storage->setLangcode($dir->getFilename());
+          $config_names = $this->storage->listAll($name . '.');
+          foreach ($config_names as $config_name) {
+            $config = new Config($config_name, $this->storage, $this->typedConfig);
+            $config->delete();
+          }
+        }
+      }
+    }
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getLanguage() {
+    return $this->language;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function setLanguage(Language $language = NULL) {
+    $this->language = $language;
+    $this->storage->setLangcode($this->language->id);
+    return $this;
+  }
+
+}
diff --git a/core/modules/language/lib/Drupal/language/Config/LanguageConfigOverrideInterface.php b/core/modules/language/lib/Drupal/language/Config/LanguageConfigOverrideInterface.php
new file mode 100644
index 0000000..63467e7
--- /dev/null
+++ b/core/modules/language/lib/Drupal/language/Config/LanguageConfigOverrideInterface.php
@@ -0,0 +1,34 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\language\Config\LanguageConfigOverrideInterface.
+ */
+
+namespace Drupal\language\Config;
+
+use Drupal\Core\Config\ConfigFactoryOverrideInterface;
+use Drupal\Core\Language\Language;
+
+interface LanguageConfigOverrideInterface extends  ConfigFactoryOverrideInterface {
+
+  /**
+   * Gets the language object used to override configuration data.
+   *
+   * @return \Drupal\Core\Language\Language
+   *   The language object used to override configuration data.
+   */
+  public function getLanguage();
+
+  /**
+   * Sets the language to be used in configuration overrides.
+   *
+   * @param \Drupal\Core\Language\Language $language
+   *   The language object to be set on the config factory. Used to override
+   *   configuration by language.
+   *
+   * @return $this
+   */
+  public function setLanguage(Language $language = NULL);
+
+}
diff --git a/core/modules/language/lib/Drupal/language/Config/LanguageStorage.php b/core/modules/language/lib/Drupal/language/Config/LanguageStorage.php
new file mode 100644
index 0000000..3ecef1e
--- /dev/null
+++ b/core/modules/language/lib/Drupal/language/Config/LanguageStorage.php
@@ -0,0 +1,158 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\language\Config\LanguageStorage.
+ */
+
+namespace Drupal\language\Config;
+
+use Drupal\Core\Cache\CacheBackendInterface;
+use Drupal\Core\Config\CachedStorage;
+use Drupal\Core\Config\FileStorage;
+
+class LanguageStorage extends CachedStorage implements LanguageStorageInterface {
+
+  /**
+   * The langcode that determines the configuration override storage directory.
+   *
+   * @var string
+   */
+  protected $langcode;
+
+  /**
+   * Tracks whether the directory exists to prevent excessive file system reads.
+   *
+   * @var bool
+   */
+  protected $directoryExists;
+
+  /**
+   * Constructs a new CachedStorage controller.
+   *
+   * @param \Drupal\Core\Config\StorageInterface $storage
+   *   A configuration storage controller to be cached.
+   * @param \Drupal\Core\Cache\CacheBackendInterface $cache
+   *   A cache backend instance to use for caching.
+   */
+  public function __construct(CacheBackendInterface $cache) {
+    $this->cache = $cache;
+  }
+
+  /**
+   * Gets the override configuration directory for a langcode.
+   *
+   * @param string $langcode
+   *   The language langcode to get the directory for.
+   *
+   * @return string
+   *   The directory where the language override configuration is stored.
+   */
+  protected function getDirectory($langcode) {
+    return config_get_config_directory(CONFIG_ACTIVE_DIRECTORY) .'/language/' . $langcode;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function write($name, array $data) {
+    $this->ensureDirectory();
+    return parent::write($name, $data);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function delete($name) {
+    if ($this->hasDirectory()) {
+      return parent::delete($name);
+    }
+    return FALSE;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function listAll($prefix = '') {
+    if ($this->hasDirectory()) {
+      return parent::listAll($prefix);
+    }
+    return array();
+  }
+
+  /**
+   * Creates a directory if necessary.
+   */
+  protected function ensureDirectory() {
+    if (!$this->hasDirectory()) {
+      drupal_mkdir($this->directory, NULL, TRUE);
+      $this->directoryExists = TRUE;
+    }
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function setLangcode($langcode) {
+    // Reset directory check.
+    $this->directoryExists = NULL;
+    $this->langcode = $langcode;
+    $this->directory = $this->getDirectory($langcode);
+    if (empty($this->storage)) {
+      $this->storage = new FileStorage($this->directory);
+    }
+    else {
+      $this->storage->setDirectory($this->directory);
+    }
+    return $this;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function getCacheKey($name) {
+    return $this->langcode . ':' . $name;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function getCacheKeys(array $names) {
+    foreach ($names as &$name) {
+      $name = $this->getCacheKey($name);
+    }
+    return $names;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function getNameFromCacheKey($key) {
+    // Remove everything before the semicolon.
+    return substr($key, strpos($key, ':') + 1);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function getNamesFromCacheKeys($keys) {
+    foreach ($keys as &$key) {
+      $key = $this->getNameFromCacheKey($key);
+    }
+    return $keys;
+  }
+
+  /**
+   * Discovers is the directory for the langcode exists.
+   *
+   * @return bool
+   *   TRUE if the directory exists, FALSE if not.
+   */
+  protected function hasDirectory() {
+    if (!isset($this->directoryExists)) {
+      $this->directoryExists = is_dir($this->directory);
+    }
+    return $this->directoryExists;
+  }
+
+}
diff --git a/core/modules/language/lib/Drupal/language/Config/LanguageStorageInterface.php b/core/modules/language/lib/Drupal/language/Config/LanguageStorageInterface.php
new file mode 100644
index 0000000..d16bad1
--- /dev/null
+++ b/core/modules/language/lib/Drupal/language/Config/LanguageStorageInterface.php
@@ -0,0 +1,26 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\language\Config\LanguageStorage.
+ */
+
+namespace Drupal\language\Config;
+
+use Drupal\Core\Config\StorageCacheInterface;
+use Drupal\Core\Config\StorageInterface;
+
+interface LanguageStorageInterface extends StorageInterface, StorageCacheInterface {
+
+  /**
+   * Sets the langcode to determine the override configuration directory to use.
+   *
+   * @param string $langcode
+   *   The language langcode to get the directory for.
+   *
+   * @return $this
+   *   The language configuration storage.
+   */
+  public function setLangcode($langcode);
+
+}
diff --git a/core/modules/language/lib/Drupal/language/ConfigurableLanguageManager.php b/core/modules/language/lib/Drupal/language/ConfigurableLanguageManager.php
index 3e0da61..209df2e 100644
--- a/core/modules/language/lib/Drupal/language/ConfigurableLanguageManager.php
+++ b/core/modules/language/lib/Drupal/language/ConfigurableLanguageManager.php
@@ -9,11 +9,15 @@
 
 use Drupal\Component\PhpStorage\PhpStorageFactory;
 use Drupal\Component\Utility\MapArray;
+use Drupal\Core\Config\Config;
 use Drupal\Core\Config\ConfigFactoryInterface;
+use Drupal\Core\Config\TypedConfigManagerInterface;
 use Drupal\Core\Extension\ModuleHandlerInterface;
 use Drupal\Core\Language\Language;
 use Drupal\Core\Language\LanguageDefault;
 use Drupal\Core\Language\LanguageManager;
+use Drupal\language\Config\LanguageConfigOverrideInterface;
+use Drupal\language\Config\LanguageStorageInterface;
 use Symfony\Component\HttpFoundation\Request;
 
 /**
@@ -36,6 +40,27 @@ class ConfigurableLanguageManager extends LanguageManager implements Configurabl
   protected $moduleHandler;
 
   /**
+   * The language configuration override service.
+   *
+   * @var \Drupal\language\Config\LanguageConfigOverrideInterface
+   */
+  protected $configFactoryOverride;
+
+  /**
+   * The language configuration storage service.
+   *
+   * @var \Drupal\language\Config\LanguageStorageInterface
+   */
+  protected $configStorage;
+
+  /**
+   * The typed config manager.
+   *
+   * @var \Drupal\Core\Config\TypedConfigManagerInterface
+   */
+  protected $typedConfig;
+
+  /**
    * The request object.
    *
    * @var \Symfony\Component\HttpFoundation\Request
@@ -94,15 +119,26 @@ public static function rebuildServices() {
   /**
    * Constructs a new ConfigurableLanguageManager object.
    *
+   * @param \Drupal\Core\Language\LanguageDefault $default_language
+   *   The default language service.
    * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
-   *   The configuration storage service.
+   *   The configuration factory service.
    * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
    *   The module handler service.
+   * @param \Drupal\language\Config\LanguageConfigOverrideInterface $config_override
+   *   The language configuration override service.
+   * @param \Drupal\language\Config\LanguageStorageInterface $config_storage
+   *   The language configuration storage service.
+   * @param \Drupal\Core\Config\TypedConfigManagerInterface $typed_config
+   *   The typed configuration manager.
    */
-  public function __construct(LanguageDefault $default_language, ConfigFactoryInterface $config_factory, ModuleHandlerInterface $module_handler) {
+  public function __construct(LanguageDefault $default_language, ConfigFactoryInterface $config_factory, ModuleHandlerInterface $module_handler, LanguageConfigOverrideInterface $config_override, LanguageStorageInterface $config_storage, TypedConfigManagerInterface $typed_config) {
     $this->defaultLanguage = $default_language;
     $this->configFactory = $config_factory;
     $this->moduleHandler = $module_handler;
+    $this->configFactoryOverride = $config_override;
+    $this->configStorage = $config_storage;
+    $this->typedConfig = $typed_config;
   }
 
   /**
@@ -372,4 +408,32 @@ public function getLanguageSwitchLinks($type, $path) {
     return $links;
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public function setConfigOverrideLanguage(Language $language) {
+    $this->configFactoryOverride->setLanguage($language);
+    return $this;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getConfigOverrideLanguage() {
+    return $this->configFactoryOverride->getLanguage();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function config($name, Language $language) {
+    $data = $this->configStorage->setLangcode($language->id)->read($name);
+    // This is not regular configuration do not use an event dispatcher.
+    $config = new Config($name, $this->configStorage, $this->typedConfig);
+    if (!empty($data)) {
+      $config->initWithData($data);
+    }
+    return $config;
+  }
+
 }
diff --git a/core/modules/language/lib/Drupal/language/ConfigurableLanguageManagerInterface.php b/core/modules/language/lib/Drupal/language/ConfigurableLanguageManagerInterface.php
index 02c8205..9651c86 100644
--- a/core/modules/language/lib/Drupal/language/ConfigurableLanguageManagerInterface.php
+++ b/core/modules/language/lib/Drupal/language/ConfigurableLanguageManagerInterface.php
@@ -78,4 +78,17 @@ public function saveLanguageTypesConfiguration(array $config);
    */
   public function updateLockedLanguageWeights();
 
+  /**
+   * Gets a language override configuration object.
+   *
+   * @param $name
+   *   The configuration object name.
+   * @param \Drupal\Core\Language\Language $language
+   *   The language to get the configuration object for.
+   *
+   * @return \Drupal\Core\Config\Config
+   *   The language override configuration object.
+   */
+  public function config($name, Language $language);
+
 }
diff --git a/core/modules/language/lib/Drupal/language/EventSubscriber/LanguageRequestSubscriber.php b/core/modules/language/lib/Drupal/language/EventSubscriber/LanguageRequestSubscriber.php
index 2d81206..8741057 100644
--- a/core/modules/language/lib/Drupal/language/EventSubscriber/LanguageRequestSubscriber.php
+++ b/core/modules/language/lib/Drupal/language/EventSubscriber/LanguageRequestSubscriber.php
@@ -7,11 +7,10 @@
 
 namespace Drupal\language\EventSubscriber;
 
-use Drupal\Core\Config\ConfigFactoryInterface;
-use Drupal\Core\Language\Language;
 use Drupal\Core\Session\AccountInterface;
 use Drupal\Core\StringTranslation\Translator\TranslatorInterface;
 use Drupal\language\ConfigurableLanguageManagerInterface;
+use Drupal\language\Config\LanguageConfigOverride;
 use Drupal\language\LanguageNegotiatorInterface;
 use Symfony\Component\HttpKernel\HttpKernelInterface;
 use Symfony\Component\HttpKernel\KernelEvents;
@@ -52,13 +51,6 @@ class LanguageRequestSubscriber implements EventSubscriberInterface {
   protected $currentUser;
 
   /**
-   * The configuration factory.
-   *
-   * @var \Drupal\Core\Config\ConfigFactoryInterface
-   */
-  protected $configFactory;
-
-  /**
    * Constructs a LanguageRequestSubscriber object.
    *
    * @param \Drupal\language\ConfigurableLanguageManagerInterface $language_manager
@@ -69,15 +61,12 @@ class LanguageRequestSubscriber implements EventSubscriberInterface {
    *   The translation service.
    * @param \Drupal\Core\Session\AccountInterface $current_user
    *   The current active user.
-   * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
-   *   The configuration factory.
    */
-  public function __construct(ConfigurableLanguageManagerInterface $language_manager, LanguageNegotiatorInterface $negotiator, TranslatorInterface $translation, AccountInterface $current_user, ConfigFactoryInterface $config_factory) {
+  public function __construct(ConfigurableLanguageManagerInterface $language_manager, LanguageNegotiatorInterface $negotiator, TranslatorInterface $translation, AccountInterface $current_user) {
     $this->languageManager = $language_manager;
     $this->negotiator = $negotiator;
     $this->translation = $translation;
     $this->currentUser = $current_user;
-    $this->configFactory = $config_factory;
   }
 
   /**
@@ -94,7 +83,7 @@ public function onKernelRequestLanguage(GetResponseEvent $event) {
       if ($this->languageManager instanceof ConfigurableLanguageManagerInterface) {
         $this->languageManager->setNegotiator($this->negotiator);
         $this->languageManager->setRequest($request);
-        $this->configFactory->setLanguage($this->languageManager->getCurrentLanguage());
+        $this->languageManager->setConfigOverrideLanguage($this->languageManager->getCurrentLanguage());
       }
       // After the language manager has initialized, set the default langcode
       // for the string translations.
diff --git a/core/modules/language/lib/Drupal/language/LanguageServiceProvider.php b/core/modules/language/lib/Drupal/language/LanguageServiceProvider.php
index 8c11eca..4b7aac4 100644
--- a/core/modules/language/lib/Drupal/language/LanguageServiceProvider.php
+++ b/core/modules/language/lib/Drupal/language/LanguageServiceProvider.php
@@ -31,8 +31,7 @@ public function register(ContainerBuilder $container) {
         ->addArgument(new Reference('language_manager'))
         ->addArgument(new Reference('language_negotiator'))
         ->addArgument(new Reference('string_translation'))
-        ->addArgument(new Reference('current_user'))
-        ->addArgument(new Reference('config.factory'));
+        ->addArgument(new Reference('current_user'));
 
       $container->register('path_processor_language', 'Drupal\language\HttpKernel\PathProcessorLanguage')
         ->addTag('path_processor_inbound', array('priority' => 300))
@@ -52,14 +51,12 @@ public function alter(ContainerBuilder $container) {
     $definition = $container->getDefinition('language_manager');
     $definition->setClass('Drupal\language\ConfigurableLanguageManager')
       ->addArgument(new Reference('config.factory'))
-      ->addArgument(new Reference('module_handler'));
+      ->addArgument(new Reference('module_handler'))
+      ->addArgument(new Reference('language.config_factory_override'))
+      ->addArgument(new Reference('language.config_storage'))
+      ->addArgument(new Reference('config.typed'));
     if ($default_language_values = $this->getDefaultLanguageValues()) {
       $container->setParameter('language.default_values', $default_language_values);
-      // Ensure that configuration can be localised if the site is monolingual
-      // but the Language module is enabled. This is the case for monolingual
-      // sites not in English.
-      $definition = $container->getDefinition('config.factory');
-      $definition->addMethodCall('setLanguageFromDefault', array(new Reference('language.default')));
     }
   }
 
diff --git a/core/modules/locale/lib/Drupal/locale/LocaleConfigManager.php b/core/modules/locale/lib/Drupal/locale/LocaleConfigManager.php
index 353fcc6..bb9d197 100644
--- a/core/modules/locale/lib/Drupal/locale/LocaleConfigManager.php
+++ b/core/modules/locale/lib/Drupal/locale/LocaleConfigManager.php
@@ -12,6 +12,7 @@
 use Drupal\Core\Config\TypedConfigManager;
 use Drupal\Core\Config\StorageInterface;
 use Drupal\Core\Config\ConfigFactoryInterface;
+use Drupal\language\Config\LanguageStorageInterface;
 
 /**
  * Manages localized configuration type plugins.
@@ -45,6 +46,13 @@ class LocaleConfigManager extends TypedConfigManager {
   protected $configFactory;
 
   /**
+   * The language configuration storage.
+   *
+   * @var \Drupal\language\Config\LanguageStorageInterface
+   */
+  protected $languageStorage;
+
+  /**
    * Creates a new typed configuration manager.
    *
    * @param \Drupal\Core\Config\StorageInterface $configStorage
@@ -60,13 +68,16 @@ class LocaleConfigManager extends TypedConfigManager {
    *   The cache backend to use for caching the definitions.
    * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
    *   The configuration factory
+   * @param \Drupal\language\Config\LanguageStorage
+   *   The language configuration storage.
    */
-  public function __construct(StorageInterface $configStorage, StorageInterface $schemaStorage, StorageInterface $installStorage, StringStorageInterface $localeStorage, CacheBackendInterface $cache, ConfigFactoryInterface $config_factory) {
+  public function __construct(StorageInterface $configStorage, StorageInterface $schemaStorage, StorageInterface $installStorage, StringStorageInterface $localeStorage, CacheBackendInterface $cache, ConfigFactoryInterface $config_factory, LanguageStorageInterface $language_storage) {
     // Note we use the install storage for the parent constructor.
     parent::__construct($configStorage, $schemaStorage, $cache);
     $this->installStorage = $installStorage;
     $this->localeStorage = $localeStorage;
     $this->configFactory = $config_factory;
+    $this->languageStorage = $language_storage;
   }
 
   /**
@@ -133,8 +144,7 @@ protected function compareConfigData(array $default, $updated) {
    *   Configuration data to be saved, that will be only the translated values.
    */
   public function saveTranslationData($name, $langcode, array $data) {
-    $locale_name = $this->configFactory->getLanguageConfigName($langcode, $name);
-    $this->configStorage->write($locale_name, $data);
+    $this->languageStorage->setLangcode($langcode)->write($name, $data);
   }
 
   /**
@@ -146,8 +156,7 @@ public function saveTranslationData($name, $langcode, array $data) {
    *   Language code.
    */
   public function deleteTranslationData($name, $langcode) {
-    $locale_name = $this->configFactory->getLanguageConfigName($langcode, $name);
-    $this->configStorage->delete($locale_name);
+    $this->languageStorage->setLangcode($langcode)->delete($name);
   }
 
   /**
@@ -220,9 +229,9 @@ public function getStringNames(array $lids) {
    *   Language code to delete.
    */
   public function deleteLanguageTranslations($langcode) {
-    $locale_name = ConfigFactoryInterface::LANGUAGE_CONFIG_PREFIX . '.' . $langcode . '.';
-    foreach ($this->configStorage->listAll($locale_name) as $name) {
-      $this->configStorage->delete($name);
+    $this->languageStorage->setLangcode($langcode);
+    foreach ($this->languageStorage->listAll() as $name) {
+      $this->languageStorage->delete($name);
     }
   }
 
@@ -305,8 +314,7 @@ public function translateString($name, $langcode, $source, $context) {
    *   A boolean indicating if a language has configuration translations.
    */
   public function hasTranslation($name, Language $language) {
-    $locale_name = $this->configFactory->getLanguageConfigName($language->id, $name);
-    $translation = $this->configStorage->read($locale_name);
+    $translation = $this->languageStorage->setLangcode($language->id)->read($name);
     return !empty($translation);
   }
 
diff --git a/core/modules/locale/lib/Drupal/locale/Tests/LocaleConfigManagerTest.php b/core/modules/locale/lib/Drupal/locale/Tests/LocaleConfigManagerTest.php
index 16fc30b..36e51a9 100644
--- a/core/modules/locale/lib/Drupal/locale/Tests/LocaleConfigManagerTest.php
+++ b/core/modules/locale/lib/Drupal/locale/Tests/LocaleConfigManagerTest.php
@@ -22,7 +22,7 @@ class LocaleConfigManagerTest extends DrupalUnitTestBase {
    *
    * @var array
    */
-  public static $modules = array('locale', 'locale_test');
+  public static $modules = array('language', 'locale', 'locale_test');
 
   /**
    * {@inheritdoc}
@@ -39,30 +39,19 @@ public static function getInfo() {
    * Tests hasTranslation().
    */
   public function testHasTranslation() {
+    $this->installConfig(array('locale_test'));
     $locale_config_manager = new LocaleConfigManager(
-      // In contrast to the actual configuration we use the installer storage
-      // as the config storage. That way, we do not actually have to install
-      // the module and can extend DrupalUnitTestBase.
-      $this->container->get('config.storage.installer'),
+      $this->container->get('config.storage'),
       $this->container->get('config.storage.schema'),
       $this->container->get('config.storage.installer'),
       $this->container->get('locale.storage'),
       $this->container->get('cache.config'),
-      $this->container->get('config.factory')
+      $this->container->get('config.factory'),
+      $this->container->get('language.config_storage')
     );
 
     $language = new Language(array('id' => 'de'));
-    // The installer storage throws an expcetion when requesting a non-existing
-    // file.
-    try {
-      $locale_config_manager->hasTranslation('locale_test.no_translation', $language);
-    }
-    catch (StorageException $exception) {
-      $result = FALSE;
-    }
-    $this->assertIdentical(FALSE, $result);
-
-    $result = $locale_config_manager->hasTranslation('locale_test.translation', $language);
-    $this->assertIdentical(TRUE, $result);
+    $this->assertFalse($locale_config_manager->hasTranslation('locale_test.no_translation', $language), 'There is no translation for locale_test.no_translation configuration.');
+    $this->assertTrue($locale_config_manager->hasTranslation('locale_test.translation', $language), 'There is a translation for locale_test.translation configuration.');
   }
 }
diff --git a/core/modules/locale/lib/Drupal/locale/Tests/LocaleConfigTranslationTest.php b/core/modules/locale/lib/Drupal/locale/Tests/LocaleConfigTranslationTest.php
index f7c64bf..5594d25 100644
--- a/core/modules/locale/lib/Drupal/locale/Tests/LocaleConfigTranslationTest.php
+++ b/core/modules/locale/lib/Drupal/locale/Tests/LocaleConfigTranslationTest.php
@@ -171,15 +171,16 @@ function testConfigTranslation() {
     $this->assertEqual($property->getValue(), $image_style_label, 'Got the right translation for image style name after translation');
 
     // Quick test to ensure translation file exists.
-    $language_config_name = \Drupal::configFactory()->getLanguageConfigName('xx', 'image.style.medium');
-    $this->assertEqual(\Drupal::config($language_config_name)->get('label'), $image_style_label);
+    $config = \Drupal::languageManager()->config('image.style.medium', language_load('xx'));
+    $this->assertEqual($config->get('label'), $image_style_label);
 
     // Uninstall the module.
     $this->drupalPostForm('admin/modules/uninstall', array('uninstall[image]' => "image"), t('Uninstall'));
     $this->drupalPostForm(NULL, array(), t('Uninstall'));
 
     // Ensure that the translated configuration has been removed.
-    $this->assertFalse(\Drupal::config($language_config_name)->get('label'), 'Translated configuration for image module removed.');
+    $config = \Drupal::languageManager()->config('image.style.medium', language_load('xx'));
+    $this->assertFalse($config->get('label'), 'Translated configuration for image module removed.');
 
     // Translate default category using the UI so configuration is refreshed.
     $category_label = $this->randomName(20);
diff --git a/core/modules/locale/locale.services.yml b/core/modules/locale/locale.services.yml
index b5f4cf4..250e648 100644
--- a/core/modules/locale/locale.services.yml
+++ b/core/modules/locale/locale.services.yml
@@ -6,7 +6,7 @@ services:
     arguments: ['@entity.manager', '@config.factory']
   locale.config.typed:
     class: Drupal\locale\LocaleConfigManager
-    arguments: ['@config.storage', '@config.storage.schema', '@config.storage.installer', '@locale.storage', '@cache.config', '@config.factory']
+    arguments: ['@config.storage', '@config.storage.schema', '@config.storage.installer', '@locale.storage', '@cache.config', '@config.factory', '@language.config_storage']
   locale.storage:
     class: Drupal\locale\StringDatabaseStorage
     arguments: ['@database']
diff --git a/core/modules/locale/tests/modules/locale_test/config/language.config.de.locale_test.translation.yml b/core/modules/locale/tests/modules/locale_test/config/language/de/locale_test.translation.yml
similarity index 100%
rename from core/modules/locale/tests/modules/locale_test/config/language.config.de.locale_test.translation.yml
rename to core/modules/locale/tests/modules/locale_test/config/language/de/locale_test.translation.yml
diff --git a/core/modules/system/lib/Drupal/system/Tests/Menu/MenuRouterRebuildTest.php b/core/modules/system/lib/Drupal/system/Tests/Menu/MenuRouterRebuildTest.php
index 7cb4df5..e71d8c0 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Menu/MenuRouterRebuildTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Menu/MenuRouterRebuildTest.php
@@ -20,7 +20,7 @@ class MenuRouterRebuildTest extends WebTestBase {
    *
    * @var array
    */
-  public static $modules = array('locale', 'menu_test');
+  public static $modules = array('language', 'menu_test');
 
   /**
    * {@inheritdoc}
@@ -48,7 +48,7 @@ function setUp() {
    */
   public function testMenuRouterRebuildContext() {
     // Enter a language context before rebuilding the menu router tables.
-    \Drupal::configFactory()->setLanguage(language_load('nl'));
+    \Drupal::languageManager()->setConfigOverrideLanguage(language_load('nl'));
     menu_router_rebuild();
 
     // Check that the language context was not used for building the menu item.
diff --git a/core/modules/system/tests/modules/menu_test/config/language.config.nl.menu_test.menu_item.yml b/core/modules/system/tests/modules/menu_test/config/language/nl/menu_test.menu_item.yml
similarity index 100%
rename from core/modules/system/tests/modules/menu_test/config/language.config.nl.menu_test.menu_item.yml
rename to core/modules/system/tests/modules/menu_test/config/language/nl/menu_test.menu_item.yml
diff --git a/core/modules/tour/tests/tour_test/config/language.config.it.tour.tour.tour-test.yml b/core/modules/tour/tests/tour_test/config/language/it/tour.tour.tour-test.yml
similarity index 100%
rename from core/modules/tour/tests/tour_test/config/language.config.it.tour.tour.tour-test.yml
rename to core/modules/tour/tests/tour_test/config/language/it/tour.tour.tour-test.yml
diff --git a/core/modules/user/user.module b/core/modules/user/user.module
index bd8e6ee..47e2fae 100644
--- a/core/modules/user/user.module
+++ b/core/modules/user/user.module
@@ -1380,13 +1380,13 @@ function user_view_multiple($accounts, $view_mode = 'full', $langcode = NULL) {
  */
 function user_mail($key, &$message, $params) {
   $token_service = \Drupal::token();
+  $language_manager = \Drupal::languageManager();
   $langcode = $message['langcode'];
   $variables = array('user' => $params['account']);
 
-  $original_language = \Drupal::configFactory()->getLanguage();
-
   $language = language_load($params['account']->getPreferredLangcode());
-  \Drupal::configFactory()->setLanguage($language);
+  $original_language = $language_manager->getConfigOverrideLanguage();
+  $language_manager->setConfigOverrideLanguage($language);
   $mail_config = \Drupal::config('user.mail');
 
    // We do not sanitize the token replacement, since the output of this
@@ -1395,7 +1395,8 @@ function user_mail($key, &$message, $params) {
   $message['subject'] .= $token_service->replace($mail_config->get($key . '.subject'), $variables, $token_options);
   $message['body'][] = $token_service->replace($mail_config->get($key . '.body'), $variables, $token_options);
 
-  \Drupal::configFactory()->setLanguage($original_language);
+  $language_manager->setConfigOverrideLanguage($original_language);
+
 }
 
 /**
