diff --git a/core/core.services.yml b/core/core.services.yml
index a58f779..6187b77 100644
--- a/core/core.services.yml
+++ b/core/core.services.yml
@@ -1,7 +1,7 @@
 services:
   cache_factory:
     class: Drupal\Core\Cache\CacheFactory
-    arguments: ['@settings']
+    arguments: ['@settings', '%cache_bin_default_backends%']
     calls:
       - [setContainer, ['@service_container']]
   cache_contexts:
@@ -45,10 +45,17 @@ services:
   cache.bootstrap:
     class: Drupal\Core\Cache\CacheBackendInterface
     tags:
-      - { name: cache.bin }
+      - { name: cache.bin, default_backend: cache.backend.chainedfast }
     factory_method: get
     factory_service: cache_factory
     arguments: [bootstrap]
+  cache.config:
+    class: Drupal\Core\Cache\CacheBackendInterface
+    tags:
+      - { name: cache.bin, default_backend: cache.backend.chainedfast }
+    factory_method: get
+    factory_service: cache_factory
+    arguments: [config]
   cache.default:
     class: Drupal\Core\Cache\CacheBackendInterface
     tags:
@@ -87,7 +94,7 @@ services:
   cache.discovery:
     class: Drupal\Core\Cache\CacheBackendInterface
     tags:
-      - { name: cache.bin }
+      - { name: cache.bin, default_backend: cache.backend.chainedfast }
     factory_method: get
     factory_service: cache_factory
     arguments: [discovery]
@@ -104,7 +111,8 @@ services:
     class: Drupal\Core\Config\ConfigInstaller
     arguments: ['@config.factory', '@config.storage', '@config.typed', '@config.manager', '@event_dispatcher']
   config.storage:
-    alias: config.storage.active
+    class: Drupal\Core\Config\CachedStorage
+    arguments: ['@config.storage.active', '@cache_factory']
   config.storage.active:
     class: Drupal\Core\Config\DatabaseStorage
     arguments: ['@database', 'config']
diff --git a/core/lib/Drupal/Core/Cache/CacheFactory.php b/core/lib/Drupal/Core/Cache/CacheFactory.php
index a3b5a01..8fd807d 100644
--- a/core/lib/Drupal/Core/Cache/CacheFactory.php
+++ b/core/lib/Drupal/Core/Cache/CacheFactory.php
@@ -27,13 +27,30 @@ class CacheFactory implements CacheFactoryInterface,  ContainerAwareInterface {
   protected $settings;
 
   /**
+   * A map of cache bin to default cache backend service name.
+   *
+   * All mappings in $settings takes precedence over this, but this can be used
+   * to optimize cache storage for a Drupal installation without cache
+   * customizations in settings.php. For example, this can be used to map the
+   * 'bootstrap' bin to 'cache.backend.chainedfast', while allowing other bins
+   * to fallback to the global default of 'cache.backend.database'.
+   *
+   * @var array
+   */
+  protected $binDefaultBackends;
+
+  /**
    * Constructs CacheFactory object.
    *
    * @param \Drupal\Core\Site\Settings $settings
    *   The settings array.
+   * @param array $bin_default_backends
+   *   (optional) A mapping of bin to backend service name. Mappings in
+   *   $settings take precedence over this.
    */
-  function __construct(Settings $settings) {
+  function __construct(Settings $settings, array $bin_default_backends = array()) {
     $this->settings = $settings;
+    $this->binDefaultBackends = $bin_default_backends;
   }
 
   /**
@@ -59,6 +76,9 @@ public function get($bin) {
     elseif (isset($cache_settings['default'])) {
       $service_name = $cache_settings['default'];
     }
+    elseif (isset($this->binDefaultBackends[$bin])) {
+      $service_name = $this->binDefaultBackends[$bin];
+    }
     else {
       $service_name = 'cache.backend.database';
     }
diff --git a/core/lib/Drupal/Core/Cache/ChainedFastBackend.php b/core/lib/Drupal/Core/Cache/ChainedFastBackend.php
index 6a825af..7cd401e 100644
--- a/core/lib/Drupal/Core/Cache/ChainedFastBackend.php
+++ b/core/lib/Drupal/Core/Cache/ChainedFastBackend.php
@@ -19,9 +19,11 @@
  * Mecached or Redis, and will be used by all web nodes, thus making it
  * consistent, but also require a network round trip for each cache get.
  *
- * It is expected this backend will be used primarily on sites running on
- * multiple web nodes, as single-node configurations can just use the fast
- * cache backend directly.
+ * In addition to being useful for sites running on multiple web nodes, this
+ * backend can also be useful for sites running on a single web node where the
+ * fast backend (e.g., APCu) isn't shareable between the web and CLI processes.
+ * Singe-node configurations that don't have that limitation can just use the
+ * fast cache backend directly.
  *
  * We always use the fast backend when reading (get()) entries from cache, but
  * check whether they were created before the last write (set()) to this
@@ -68,11 +70,37 @@ class ChainedFastBackend implements CacheBackendInterface {
   /**
    * The time at which the last write to this cache bin happened.
    *
-   * @var int
+   * @var float
    */
   protected $lastWriteTimestamp;
 
   /**
+   * The time at which the last write timestamp was fetched.
+   *
+   * @var float
+   */
+  protected $lastWriteTimestampFetchTime = 0.0;
+
+  /**
+   * How long, in seconds, the last write timestamp is valid.
+   *
+   * The last write timestamp is checked at least once per instantiation of
+   * this class (i.e., once per bin per PHP request). To minimize network
+   * traffic to the consistent backend, it is not rechecked within the same
+   * instance for this TTL duration. As a result, during this TTL window, it is
+   * possible for a cache invalidation that happens in a parallel request to
+   * not propagate to this request, but that is also the case anywhere that a
+   * static cache is used.
+   *
+   * 300ms is longer than most simple web requests, but lets long running
+   * requests (e.g., complex pages or command line processes) stay reasonably
+   * synchronized with changes happening in parallel requests.
+   *
+   * @var float
+   */
+  protected $lastWriteTimestampTtl = 0.3;
+
+  /**
    * Constructs a ChainedFastBackend object.
    *
    * @param \Drupal\Core\Cache\CacheBackendInterface $consistent_backend
@@ -102,14 +130,47 @@ public function get($cid, $allow_invalid = FALSE) {
    * {@inheritdoc}
    */
   public function getMultiple(&$cids, $allow_invalid = FALSE) {
-    // Retrieve as many cache items as possible from the fast backend. (Some
-    // cache entries may have been created before the last write to this cache
-    // bin and therefore be stale/wrong/inconsistent.)
     $cids_copy = $cids;
     $cache = array();
+
+    // If we can determine the time at which the last write to the consistent
+    // backend occurred (we might not be able to if it has been recently
+    // flushed/restarted), then we can use that to validate items from the fast
+    // backend, so try to get those first. Otherwise, we can't assume that
+    // anything in the fast backend is valid, so don't even bother fetching
+    // from there.
     $last_write_timestamp = $this->getLastWriteTimestamp();
     if ($last_write_timestamp) {
-      foreach ($this->fastBackend->getMultiple($cids, $allow_invalid) as $item) {
+      // Items in the fast backend might be invalid based on their timestamp,
+      // but we can't check the timestamp prior to getting the item, which
+      // includes unserializing it. However, unserializing an invalid item can
+      // throw an exception. For example, a __wakeup() implementation that
+      // receives object properties containing references to code or data that
+      // no longer exists in the application's current state).
+      //
+      // Unserializing invalid data, whether it throws an exception or not, is
+      // a waste of time, but we only incur it while a cache invalidation has
+      // not yet finished propagating to all the fast backend instances.
+      //
+      // Most cache backend implementations should not wrap their internal
+      // get() implementations with a try/catch, because they have no reason to
+      // assume that their data is invalid, and doing so would mask
+      // unserialization errors of valid data. We do so here, only because the
+      // fast backend is non-authoritative, and after discarding its
+      // exceptions, we proceed to check the consistent (authoritative) backend
+      // and allow exceptions from that to bubble up.
+      try {
+        $items = $this->fastBackend->getMultiple($cids, $allow_invalid);
+      }
+      catch (\Exception $e) {
+        $cids = $cids_copy;
+        $items = array();
+      }
+
+      // Even if items were successfully fetched from the fast backend, they
+      // are potentially invalid if older than the last time the bin was
+      // written to in the consistent backend, so only keep ones that aren't.
+      foreach ($items as $item) {
         if ($item->created < $last_write_timestamp) {
           $cids[array_search($item->cid, $cids_copy)] = $item->cid;
         }
@@ -233,7 +294,10 @@ public function removeBin() {
    * Gets the last write timestamp.
    */
   protected function getLastWriteTimestamp() {
-    if ($this->lastWriteTimestamp === NULL) {
+    $now = microtime(TRUE);
+    $timestamp_fetch_time_plus_ttl = $this->lastWriteTimestampFetchTime + $this->lastWriteTimestampTtl;
+    if ($this->lastWriteTimestamp === NULL || ($now > $timestamp_fetch_time_plus_ttl)) {
+      $this->lastWriteTimestampFetchTime = $now;
       $cache = $this->consistentBackend->get(self::LAST_WRITE_TIMESTAMP_PREFIX . $this->bin);
       $this->lastWriteTimestamp = $cache ? $cache->data : 0;
     }
diff --git a/core/lib/Drupal/Core/Cache/ChainedFastBackendFactory.php b/core/lib/Drupal/Core/Cache/ChainedFastBackendFactory.php
index 8d8fcf4..5353eba 100644
--- a/core/lib/Drupal/Core/Cache/ChainedFastBackendFactory.php
+++ b/core/lib/Drupal/Core/Cache/ChainedFastBackendFactory.php
@@ -6,11 +6,57 @@
  */
 
 namespace Drupal\Core\Cache;
+use Drupal\Core\Site\Settings;
+use Symfony\Component\DependencyInjection\ContainerAwareTrait;
 
 /**
  * Defines the chained fast cache backend factory.
  */
-class ChainedFastBackendFactory extends CacheFactory {
+class ChainedFastBackendFactory implements CacheFactoryInterface {
+
+  use ContainerAwareTrait;
+
+  /**
+   * The service name for the consistent backend.
+   *
+   * @var string
+   */
+  protected $consistentService;
+
+  /**
+   * The service name for the fast backend.
+   *
+   * @var string
+   */
+  protected $fastService;
+
+  /**
+   * Constructs ChainedFastBackendFactory object.
+   *
+   * @param \Drupal\Core\Site\Settings $settings
+   *   The settings array.
+   */
+  function __construct(Settings $settings) {
+    // Allow settings to specify the two backend services to use.
+    $cache_settings = $settings->get('cache');
+    if (isset($cache_settings['chained_fast_cache']) && is_array($cache_settings['chained_fast_cache'])) {
+      if (!empty($cache_settings['chained_fast_cache']['consistent'])) {
+        $this->consistentService = $cache_settings['chained_fast_cache']['consistent'];
+      }
+      if (!empty($cache_settings['chained_fast_cache']['fast'])) {
+        $this->fastService = $cache_settings['chained_fast_cache']['fast'];
+      }
+    }
+
+    // Otherwise, default to database for the consistent backend, and to the
+    // APCu (if it's available) for the fast backend.
+    if (!isset($this->consistentService)) {
+      $this->consistentService = 'cache.backend.database';
+    }
+    if (!isset($this->fastService) && function_exists('apc_fetch')) {
+      $this->fastService = 'cache.backend.apcu';
+    }
+  }
 
   /**
    * Instantiates a chained, fast cache backend class for a given cache bin.
@@ -22,24 +68,19 @@ class ChainedFastBackendFactory extends CacheFactory {
    *   The cache backend object associated with the specified bin.
    */
   public function get($bin) {
-    $consistent_service = 'cache.backend.database';
-    $fast_service = 'cache.backend.apcu';
+    $backend = $this->container->get($this->consistentService)->get($bin);
 
-    $cache_settings = $this->settings->get('cache');
-    if (isset($cache_settings['chained_fast_cache']) && is_array($cache_settings['chained_fast_cache'])) {
-      if (!empty($cache_settings['chained_fast_cache']['consistent'])) {
-        $consistent_service = $cache_settings['chained_fast_cache']['consistent'];
-      }
-      if (!empty($cache_settings['chained_fast_cache']['fast'])) {
-        $fast_service = $cache_settings['chained_fast_cache']['fast'];
-      }
+    // Use the chained backend only if there is a fast backend available;
+    // otherwise, just return the consistent backend directly.
+    if (isset($this->fastService)) {
+      $backend = new ChainedFastBackend(
+        $backend,
+        $this->container->get($this->fastService)->get($bin),
+        $bin
+      );
     }
 
-    return new ChainedFastBackend(
-      $this->container->get($consistent_service)->get($bin),
-      $this->container->get($fast_service)->get($bin),
-      $bin
-    );
+    return $backend;
   }
 
 }
diff --git a/core/lib/Drupal/Core/Cache/ListCacheBinsPass.php b/core/lib/Drupal/Core/Cache/ListCacheBinsPass.php
index 5381186..34be13e 100644
--- a/core/lib/Drupal/Core/Cache/ListCacheBinsPass.php
+++ b/core/lib/Drupal/Core/Cache/ListCacheBinsPass.php
@@ -22,9 +22,15 @@ class ListCacheBinsPass implements CompilerPassInterface {
    */
   public function process(ContainerBuilder $container) {
     $cache_bins = array();
+    $cache_bin_default_backends = array();
     foreach ($container->findTaggedServiceIds('cache.bin') as $id => $attributes) {
-      $cache_bins[$id] = substr($id, strpos($id, '.') + 1);
+      $bin = substr($id, strpos($id, '.') + 1);
+      $cache_bins[$id] = $bin;
+      if (isset($attributes[0]['default_backend'])) {
+        $cache_bin_default_backends[$bin] = $attributes[0]['default_backend'];
+      }
     }
     $container->setParameter('cache_bins', $cache_bins);
+    $container->setParameter('cache_bin_default_backends', $cache_bin_default_backends);
   }
 }
diff --git a/core/lib/Drupal/Core/Config/CachedStorage.php b/core/lib/Drupal/Core/Config/CachedStorage.php
index 30ad1f7..f34e9f5 100644
--- a/core/lib/Drupal/Core/Config/CachedStorage.php
+++ b/core/lib/Drupal/Core/Config/CachedStorage.php
@@ -9,6 +9,7 @@
 
 use Drupal\Core\Cache\Cache;
 use Drupal\Core\Cache\CacheFactoryInterface;
+use Drupal\Core\DependencyInjection\DependencySerializationTrait;
 
 /**
  * Defines the cached storage.
@@ -18,6 +19,7 @@
  * handles cache invalidation.
  */
 class CachedStorage implements StorageInterface, StorageCacheInterface {
+  use DependencySerializationTrait;
 
   /**
    * The configuration storage to be cached.
diff --git a/core/modules/language/src/Config/LanguageConfigFactoryOverride.php b/core/modules/language/src/Config/LanguageConfigFactoryOverride.php
index 24c4bf5..1349e43 100644
--- a/core/modules/language/src/Config/LanguageConfigFactoryOverride.php
+++ b/core/modules/language/src/Config/LanguageConfigFactoryOverride.php
@@ -169,7 +169,7 @@ public function createConfigObject($name, $collection = StorageInterface::DEFAUL
    *   The configuration collection name for a langcode.
    */
   protected function createConfigCollectionName($langcode) {
-    return 'language.' . $langcode;
+    return 'language.' . str_replace('-', '_', $langcode);
   }
 
   /**
@@ -192,7 +192,9 @@ protected function getLangcodeFromCollectionName($collection) {
     if (!isset($matches[1])) {
       throw new \InvalidArgumentException(String::format('!collection is not a valid language override collection', array('!collection' => $collection)));
     }
-    return $matches[1];
+    // @todo This returns the incorrect language code if it originally
+    //   contained an underscore: https://www.drupal.org/node/2312189.
+    return str_replace('_', '-', $matches[1]);
   }
 
   /**
diff --git a/core/modules/simpletest/src/KernelTestBase.php b/core/modules/simpletest/src/KernelTestBase.php
index 616d064..25dedc1 100644
--- a/core/modules/simpletest/src/KernelTestBase.php
+++ b/core/modules/simpletest/src/KernelTestBase.php
@@ -256,7 +256,7 @@ public function containerBuild(ContainerBuilder $container) {
     $container->register('cache_factory', 'Drupal\Core\Cache\MemoryBackendFactory');
 
     $container
-      ->register('config.storage.active', 'Drupal\Core\Config\DatabaseStorage')
+      ->register('config.storage', 'Drupal\Core\Config\DatabaseStorage')
       ->addArgument(Database::getConnection())
       ->addArgument('config');
 
diff --git a/core/modules/simpletest/src/WebTestBase.php b/core/modules/simpletest/src/WebTestBase.php
index 956080a..5473a96 100644
--- a/core/modules/simpletest/src/WebTestBase.php
+++ b/core/modules/simpletest/src/WebTestBase.php
@@ -1147,6 +1147,9 @@ protected function resetAll() {
    */
   protected function refreshVariables() {
     // Clear the tag cache.
+    // @todo Replace drupal_static() usage within classes and also reset the
+    //   protected $lastWriteTimestamp of Drupal\Core\Cache\ChainedFastBackend:
+    //   https://www.drupal.org/node/2311945.
     drupal_static_reset('Drupal\Core\Cache\CacheBackendInterface::tagCache');
     drupal_static_reset('Drupal\Core\Cache\DatabaseBackend::deletedTags');
     drupal_static_reset('Drupal\Core\Cache\DatabaseBackend::invalidatedTags');
