diff --git a/core/core.services.yml b/core/core.services.yml
index dec001f..9daefe1 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_default_bin_backends%']
     calls:
       - [setContainer, ['@service_container']]
   cache_contexts:
@@ -41,10 +41,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:
@@ -83,7 +90,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]
@@ -100,7 +107,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..3345367 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 $defaultBinBackends;
+
+  /**
    * Constructs CacheFactory object.
    *
    * @param \Drupal\Core\Site\Settings $settings
    *   The settings array.
+   * @param array $default_bin_backends
+   *   (optional) A mapping of bin to backend service name. Mappings in
+   *   $settings take precedence over this.
    */
-  function __construct(Settings $settings) {
+  public function __construct(Settings $settings, array $default_bin_backends = array()) {
     $this->settings = $settings;
+    $this->defaultBinBackends = $default_bin_backends;
   }
 
   /**
@@ -59,6 +76,9 @@ public function get($bin) {
     elseif (isset($cache_settings['default'])) {
       $service_name = $cache_settings['default'];
     }
+    elseif (isset($this->defaultBinBackends[$bin])) {
+      $service_name = $this->defaultBinBackends[$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..7794781 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.
+ * Single-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;
         }
@@ -230,10 +291,20 @@ public function removeBin() {
   }
 
   /**
+   * @todo Document in https://www.drupal.org/node/2311945.
+   */
+  public function reset() {
+    $this->lastWriteTimestamp = NULL;
+  }
+
+  /**
    * 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..8e95776 100644
--- a/core/lib/Drupal/Core/Cache/ChainedFastBackendFactory.php
+++ b/core/lib/Drupal/Core/Cache/ChainedFastBackendFactory.php
@@ -6,40 +6,80 @@
  */
 
 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;
 
   /**
-   * Instantiates a chained, fast cache backend class for a given cache bin.
+   * The service name for the consistent backend.
    *
-   * @param string $bin
-   *   The cache bin for which a cache backend object should be returned.
+   * @var string
+   */
+  protected $consistentService;
+
+  /**
+   * The service name for the fast backend.
    *
-   * @return \Drupal\Core\Cache\CacheBackendInterface
-   *   The cache backend object associated with the specified bin.
+   * @var string
    */
-  public function get($bin) {
-    $consistent_service = 'cache.backend.database';
-    $fast_service = 'cache.backend.apcu';
+  protected $fastService;
 
-    $cache_settings = $this->settings->get('cache');
-    if (isset($cache_settings['chained_fast_cache']) && is_array($cache_settings['chained_fast_cache'])) {
+  /**
+   * Constructs ChainedFastBackendFactory object.
+   *
+   * @param \Drupal\Core\Site\Settings $settings
+   *   The settings array.
+   */
+  public 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'])) {
       if (!empty($cache_settings['chained_fast_cache']['consistent'])) {
-        $consistent_service = $cache_settings['chained_fast_cache']['consistent'];
+        $this->consistentService = $cache_settings['chained_fast_cache']['consistent'];
       }
       if (!empty($cache_settings['chained_fast_cache']['fast'])) {
-        $fast_service = $cache_settings['chained_fast_cache']['fast'];
+        $this->fastService = $cache_settings['chained_fast_cache']['fast'];
       }
     }
 
-    return new ChainedFastBackend(
-      $this->container->get($consistent_service)->get($bin),
-      $this->container->get($fast_service)->get($bin),
-      $bin
-    );
+    // 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.
+   *
+   * @param string $bin
+   *   The cache bin for which a cache backend object should be returned.
+   *
+   * @return \Drupal\Core\Cache\CacheBackendInterface
+   *   The cache backend object associated with the specified bin.
+   */
+  public function get($bin) {
+    // Use the chained backend only if there is a fast backend available;
+    // otherwise, just return the consistent backend directly.
+    if (isset($this->fastService)) {
+      return new ChainedFastBackend(
+        $this->container->get($this->consistentService)->get($bin),
+        $this->container->get($this->fastService)->get($bin),
+        $bin
+      );
+    }
+    else {
+      return $this->container->get($this->consistentService)->get($bin);
+    }
   }
 
 }
diff --git a/core/lib/Drupal/Core/Cache/ListCacheBinsPass.php b/core/lib/Drupal/Core/Cache/ListCacheBinsPass.php
index 5381186..e9e7158 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_default_bin_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_default_bin_backends[$bin] = $attributes[0]['default_backend'];
+      }
     }
     $container->setParameter('cache_bins', $cache_bins);
+    $container->setParameter('cache_default_bin_backends', $cache_default_bin_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 afea590..58b2e94 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 a12c310..bdeaaaf 100644
--- a/core/modules/simpletest/src/WebTestBase.php
+++ b/core/modules/simpletest/src/WebTestBase.php
@@ -11,6 +11,7 @@
 use Drupal\Component\Utility\Crypt;
 use Drupal\Component\Utility\NestedArray;
 use Drupal\Component\Utility\String;
+use Drupal\Core\Cache\Cache;
 use Drupal\Core\DrupalKernel;
 use Drupal\Core\Database\Database;
 use Drupal\Core\Database\ConnectionNotDefinedException;
@@ -1144,9 +1145,17 @@ protected function resetAll() {
    */
   protected function refreshVariables() {
     // Clear the tag cache.
+    // @todo Replace drupal_static() usage within classes and provide a
+    //   proper interface for invoking reset() on a cache backend:
+    //   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');
+    foreach (Cache::getBins() as $backend) {
+      if (is_callable(array($backend, 'reset'))) {
+        $backend->reset();
+      }
+    }
 
     $this->container->get('config.factory')->reset();
     $this->container->get('state')->resetCache();
