diff --git a/core/lib/Drupal/Core/Cache/MultiBackend.php b/core/lib/Drupal/Core/Cache/MultiBackend.php
new file mode 100644
index 0000000..b8a6553
--- /dev/null
+++ b/core/lib/Drupal/Core/Cache/MultiBackend.php
@@ -0,0 +1,355 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\Cache\MultiBackend.
+ */
+
+namespace Drupal\Core\Cache;
+
+/**
+ * A proxy cache backend to preload multiple items.
+ */
+class MultiBackend implements CacheBackendInterface, CacheTagsInvalidatorInterface {
+
+  /**
+   * The cache backend being decorated.
+   *
+   * @var \Drupal\Core\Cache\CacheBackendInterface
+   */
+  protected $cacheBackend;
+
+  /**
+   * The cache bin name.
+   *
+   * @var string
+   */
+  protected $bin;
+
+  /**
+   * The cache key used to store the multi get keys.
+   *
+   * @var string
+   */
+  protected $multiCidKey;
+
+  /**
+   * An array of multiple cache IDs this backend is using.
+   *
+   * @var array
+   */
+  protected $multiCids = [];
+
+  /**
+   * The loaded cache items.
+   *
+   * @var array
+   */
+  protected $cacheItems = [];
+
+  /**
+   * Constructs a MultiBackend object.
+   *
+   * @param \Drupal\Core\Cache\CacheBackendInterface $cache_backend
+   *   The cache backend.
+   * @param string $bin
+   *   The cache bin for which the object is created.
+   */
+  public function __construct(CacheBackendInterface $cache_backend, $bin) {
+    $this->cacheBackend = $cache_backend;
+    $this->bin = $bin;
+    $this->multiCidKey = 'cache_multi_' . $bin;
+
+    // @todo Lazy load this?
+    $this->preloadMultiple();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function get($cid, $allow_invalid = FALSE) {
+    // Try to get the cache item from the preloaded data, otherwise delegate to
+    // the storage backend.
+    return isset($this->cacheItems[$cid]) ? $this->prepareItem($this->cacheItems[$cid], $allow_invalid) : $this->cacheBackend->get($cid, $allow_invalid);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getMultiple(&$cids, $allow_invalid = FALSE) {
+    $ret = [];
+    $items = array_intersect_key($this->cacheItems, array_flip($cids));
+
+    foreach ($items as $item) {
+      $item = $this->prepareItem($item, $allow_invalid);
+      if ($item) {
+        $ret[$item->cid] = $item;
+      }
+    }
+
+    $cids = array_diff($cids, array_keys($ret));
+
+    if ($cids) {
+      foreach ($this->cacheBackend->getMultiple($cids, $allow_invalid) as $item) {
+        $ret[$item->cid] = $item;
+      }
+
+      $cids = array_diff($cids, array_keys($ret));
+    }
+
+    return $ret;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function set($cid, $data, $expire = Cache::PERMANENT, array $tags = array()) {
+    $this->cacheBackend->set($cid, $data, $expire, $tags);
+
+    $this->cacheItems[$cid] = $this->createCacheObject($cid, $data, $expire, $tags);
+    $this->addMultiKeys([$cid]);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function setMultiple(array $items = []) {
+    $this->cacheBackend->setMultiple($items);
+
+    foreach ($items as $cid => $item) {
+      $item += [
+        'expire' => Cache::PERMANENT,
+        'tags' => [],
+      ];
+      $this->cacheItems[$cid] = $this->createCacheObject($cid, $item['data'], $item['expire'], $item['tags']);
+    }
+
+    // Map keys and store them.
+    $this->addMultiKeys(array_keys($items));
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function delete($cid) {
+    unset($this->cacheItems[$cid]);
+    $this->cacheBackend->delete($cid);
+    $this->removeMultiKeys([$cid]);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function deleteMultiple(array $cids) {
+    foreach ($cids as $cid) {
+      unset($this->cacheItems[$cid]);
+    }
+
+    $this->cacheBackend->deleteMultiple($cids);
+    $this->removeMultiKeys($cids);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function deleteAll() {
+    $this->cacheItems = [];
+    $keys = array_merge($this->multiCids, [$this->multiCidKey]);
+    $this->cacheBackend->deleteMultiple($keys);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function invalidate($cid) {
+    if (isset($this->cacheItems[$cid])) {
+      $this->cacheItems[$cid]->expire = $this->getRequestTime() - 1;
+    }
+
+    $this->cacheBackend->invalidate($cid);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function invalidateMultiple(array $cids) {
+    foreach ($cids as $cid) {
+      if (isset($this->cacheItems[$cid])) {
+        $this->cacheItems[$cid]->expire = $this->getRequestTime() - 1;
+      }
+    }
+
+    $this->cacheBackend->invalidateMultiple($cids);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function invalidateAll() {
+    // Invalidate all static items.
+    foreach ($this->cacheItems as $cid => $item) {
+      $this->cacheItems[$cid]->expire = $this->getRequestTime() - 1;
+    }
+
+    // Invalidate all items for the storeage backend, including the mutli list.
+    $keys = array_merge($this->multiCids, [$this->multiCidKey]);
+    $this->cacheBackend->invalidateMultiple($keys);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function invalidateTags(array $tags) {
+    foreach ($this->cacheItems as $cid => $item) {
+      if (array_intersect($tags, $item->tags)) {
+        $this->cacheItems[$cid]->expire = $this->getRequestTime() - 1;
+      }
+    }
+
+    $this->cacheBackend->invalidateTags($tags);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function garbageCollection() {
+    $this->cacheBackend->garbageCollection();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function removeBin() {
+    $this->cacheItems = [];
+    $this->resetMultiKeys();
+
+    $this->cacheBackend->removeBin();
+  }
+
+  /**
+   * Pre load Multiple items.
+   */
+  protected function preloadMultiple() {
+    $multi_cid_cache = $this->cacheBackend->get($this->multiCidKey);
+
+    // Return now if there are no cids to load.
+    if (empty($multi_cid_cache->data)) {
+      return;
+    }
+
+    $this->multiCids = $multi_cid_cache->data;
+    $this->cacheItems = $this->cacheBackend->getMultiple($this->multiCids);
+
+    // If the loaded items and the multi cids are different reset them.
+    if (array_diff_key($this->cacheItems, $this->multiCids)) {
+      $this->resetMultiKeys();
+      $this->addMultiKeys(array_keys($this->cacheItems));
+    }
+  }
+
+  /**
+   * Prepares a cached item.
+   *
+   * Checks that items are either permanent or did not expire, and returns data
+   * as appropriate.
+   *
+   * @param object $cache
+   *   An item loaded from cache_get() or cache_get_multiple().
+   * @param bool $allow_invalid
+   *   (optional) If TRUE, cache items may be returned even if they have expired
+   *   or been invalidated.
+   *
+   * @return mixed
+   *   The item with data as appropriate or FALSE if there is no
+   *   valid item to load.
+   */
+  protected function prepareItem($cache, $allow_invalid) {
+    if (!isset($cache->data)) {
+      return FALSE;
+    }
+
+    // The object passed into this function is the one stored in $this->cache.
+    // We must clone it as part of the preparation step so that the actual
+    // cache object is not affected by manipulations of the returned object.
+    $prepared = clone $cache;
+
+    if (is_object($prepared->data)) {
+      $prepared->data = clone $cache->data;
+    }
+
+    // Check expire time.
+    $prepared->valid = ($prepared->expire === Cache::PERMANENT) || ($prepared->expire >= $this->getRequestTime());
+
+    if (!$allow_invalid && !$prepared->valid) {
+      return FALSE;
+    }
+
+    return $prepared;
+  }
+
+  /**
+   * Adds a multi cache key.
+   *
+   * @param array $keys
+   */
+  protected function addMultiKeys(array $keys) {
+    foreach ($keys as $key) {
+      $this->multiCids[$key] = $key;
+    }
+
+    // @todo Move this to set on destruct?
+    $this->cacheBackend->set($this->multiCidKey, $this->multiCids);
+  }
+
+  /**
+   * Removes a multi cache key.
+   *
+   * @param array $keys
+   */
+  protected function removeMultiKeys(array $keys) {
+    foreach ($keys as $key) {
+      unset($this->multiCids[$key]);
+    }
+
+    $this->cacheBackend->set($this->multiCidKey, $this->multiCids);
+  }
+
+  /**
+   * Resets multi cache keys.
+   */
+  protected function resetMultiKeys() {
+    $this->cacheBackend->delete($this->multiCidKey);
+    $this->multiCids = [];
+  }
+
+  /**
+   * Creates a cache object.
+   *
+   * @param $cid
+   * @param $data
+   * @param $expire
+   * @param array $tags
+   *
+   * @return \stdClass
+   */
+  protected function createCacheObject($cid, $data, $expire = Cache::PERMANENT, array $tags = []) {
+    return (object) [
+      'cid' => $cid,
+      'data' => is_object($data) ? clone $data : $data,
+      'expire' => $expire,
+      'created' => round(microtime(TRUE), 3),
+      'tags' => $tags,
+      'serialized' => FALSE,
+    ];
+  }
+
+  /**
+   * Wrapper method for REQUEST_TIME constant.
+   *
+   * @return int
+   */
+  protected function getRequestTime() {
+    return defined('REQUEST_TIME') ? REQUEST_TIME : (int) $_SERVER['REQUEST_TIME'];
+  }
+
+}
diff --git a/core/modules/system/src/Tests/Cache/MultiBackendUnitTest.php b/core/modules/system/src/Tests/Cache/MultiBackendUnitTest.php
new file mode 100644
index 0000000..793ec83
--- /dev/null
+++ b/core/modules/system/src/Tests/Cache/MultiBackendUnitTest.php
@@ -0,0 +1,33 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\system\Tests\Cache\MultiBackendUnitTest.
+ */
+
+namespace Drupal\system\Tests\Cache;
+
+use Drupal\Core\Cache\MemoryBackend;
+use Drupal\Core\Cache\MultiBackend;
+
+/**
+ * Unit test of the multi backend using the generic cache unit test base.
+ *
+ * @group Cache
+ */
+class MultiBackendUnitTest extends GenericCacheBackendUnitTestBase {
+
+  /**
+   * Creates a new MultiBackend instance.
+   *
+   * @return \Drupal\Core\Cache\MultiBackend
+   *   A new MultiBackend object.
+   */
+  protected function createCacheBackend($bin) {
+    $multi = new MultiBackend(new MemoryBackend('foo'), $bin);
+    \Drupal::service('cache_tags.invalidator')->addInvalidator($multi);
+
+    return $multi;
+  }
+
+}
diff --git a/core/modules/views/views.services.yml b/core/modules/views/views.services.yml
index 1a01543..6346fb8 100644
--- a/core/modules/views/views.services.yml
+++ b/core/modules/views/views.services.yml
@@ -1,61 +1,64 @@
 services:
+  cache.views_plugin:
+    class: Drupal\Core\Cache\MultiBackend
+    arguments: ['@cache.discovery', views_plugins]
   plugin.manager.views.access:
     class: Drupal\views\Plugin\ViewsPluginManager
-    arguments: [access, '@container.namespaces', '@cache.discovery', '@module_handler']
+    arguments: [access, '@container.namespaces', '@cache.views_plugin', '@module_handler']
   plugin.manager.views.area:
     class: Drupal\views\Plugin\ViewsHandlerManager
-    arguments: [area, '@container.namespaces', '@views.views_data', '@cache.discovery', '@module_handler']
+    arguments: [area, '@container.namespaces', '@views.views_data', '@cache.views_plugin', '@module_handler']
   plugin.manager.views.argument:
     class: Drupal\views\Plugin\ViewsHandlerManager
-    arguments: [argument, '@container.namespaces', '@views.views_data', '@cache.discovery', '@module_handler']
+    arguments: [argument, '@container.namespaces', '@views.views_data', '@cache.views_plugin', '@module_handler']
   plugin.manager.views.argument_default:
     class: Drupal\views\Plugin\ViewsPluginManager
-    arguments: [argument_default, '@container.namespaces', '@cache.discovery', '@module_handler']
+    arguments: [argument_default, '@container.namespaces', '@cache.views_plugin', '@module_handler']
   plugin.manager.views.argument_validator:
     class: Drupal\views\Plugin\ViewsPluginManager
-    arguments: [argument_validator, '@container.namespaces', '@cache.discovery', '@module_handler']
+    arguments: [argument_validator, '@container.namespaces', '@cache.views_plugin', '@module_handler']
   plugin.manager.views.cache:
     class: Drupal\views\Plugin\ViewsPluginManager
-    arguments: [cache, '@container.namespaces', '@cache.discovery', '@module_handler']
+    arguments: [cache, '@container.namespaces', '@cache.views_plugin', '@module_handler']
   plugin.manager.views.display_extender:
     class: Drupal\views\Plugin\ViewsPluginManager
-    arguments: [display_extender, '@container.namespaces', '@cache.discovery', '@module_handler']
+    arguments: [display_extender, '@container.namespaces', '@cache.views_plugin', '@module_handler']
   plugin.manager.views.display:
     class: Drupal\views\Plugin\ViewsPluginManager
-    arguments: [display, '@container.namespaces', '@cache.discovery', '@module_handler']
+    arguments: [display, '@container.namespaces', '@cache.views_plugin', '@module_handler']
   plugin.manager.views.exposed_form:
     class: Drupal\views\Plugin\ViewsPluginManager
-    arguments: [exposed_form, '@container.namespaces', '@cache.discovery', '@module_handler']
+    arguments: [exposed_form, '@container.namespaces', '@cache.views_plugin', '@module_handler']
   plugin.manager.views.field:
     class: Drupal\views\Plugin\ViewsHandlerManager
-    arguments: [field, '@container.namespaces', '@views.views_data', '@cache.discovery', '@module_handler']
+    arguments: [field, '@container.namespaces', '@views.views_data', '@cache.views_plugin', '@module_handler']
   plugin.manager.views.filter:
     class: Drupal\views\Plugin\ViewsHandlerManager
-    arguments: [filter, '@container.namespaces', '@views.views_data', '@cache.discovery', '@module_handler']
+    arguments: [filter, '@container.namespaces', '@views.views_data', '@cache.views_plugin', '@module_handler']
   plugin.manager.views.join:
     class: Drupal\views\Plugin\ViewsHandlerManager
-    arguments: [join, '@container.namespaces', '@views.views_data', '@cache.discovery', '@module_handler']
+    arguments: [join, '@container.namespaces', '@views.views_data', '@cache.views_plugin', '@module_handler']
   plugin.manager.views.pager:
     class: Drupal\views\Plugin\ViewsPluginManager
-    arguments: [pager, '@container.namespaces', '@cache.discovery', '@module_handler']
+    arguments: [pager, '@container.namespaces', '@cache.views_plugin', '@module_handler']
   plugin.manager.views.query:
     class: Drupal\views\Plugin\ViewsPluginManager
-    arguments: [query, '@container.namespaces', '@cache.discovery', '@module_handler']
+    arguments: [query, '@container.namespaces', '@cache.views_plugin', '@module_handler']
   plugin.manager.views.relationship:
     class: Drupal\views\Plugin\ViewsHandlerManager
-    arguments: [relationship, '@container.namespaces', '@views.views_data', '@cache.discovery', '@module_handler']
+    arguments: [relationship, '@container.namespaces', '@views.views_data', '@cache.views_plugin', '@module_handler']
   plugin.manager.views.row:
     class: Drupal\views\Plugin\ViewsPluginManager
-    arguments: [row, '@container.namespaces', '@cache.discovery', '@module_handler']
+    arguments: [row, '@container.namespaces', '@cache.views_plugin', '@module_handler']
   plugin.manager.views.sort:
     class: Drupal\views\Plugin\ViewsHandlerManager
-    arguments: [sort, '@container.namespaces', '@views.views_data', '@cache.discovery', '@module_handler']
+    arguments: [sort, '@container.namespaces', '@views.views_data', '@cache.views_plugin', '@module_handler']
   plugin.manager.views.style:
     class: Drupal\views\Plugin\ViewsPluginManager
-    arguments: [style, '@container.namespaces', '@cache.discovery', '@module_handler']
+    arguments: [style, '@container.namespaces', '@cache.views_plugin', '@module_handler']
   plugin.manager.views.wizard:
     class: Drupal\views\Plugin\ViewsPluginManager
-    arguments: [wizard, '@container.namespaces', '@cache.discovery', '@module_handler']
+    arguments: [wizard, '@container.namespaces', '@cache.views_plugin', '@module_handler']
   views.views_data:
     class: Drupal\views\ViewsData
     arguments: ['@cache.discovery', '@config.factory', '@module_handler', '@language_manager']
