diff --git a/core/lib/Drupal/Core/Plugin/DefaultPluginManager.php b/core/lib/Drupal/Core/Plugin/DefaultPluginManager.php
new file mode 100644
index 0000000..1ce3eca
--- /dev/null
+++ b/core/lib/Drupal/Core/Plugin/DefaultPluginManager.php
@@ -0,0 +1,252 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\Plugin\DefaultPluginManager
+ */
+
+namespace Drupal\Core\Plugin;
+
+use Drupal\Component\Plugin\Discovery\DerivativeDiscoveryDecorator;
+use Drupal\Component\Plugin\PluginManagerBase;
+use Drupal\Component\Plugin\PluginManagerInterface;
+use Drupal\Component\Plugin\Factory\DefaultFactory;
+use Drupal\Component\Utility\NestedArray;
+use Drupal\Core\Cache\CacheBackendInterface;
+use Drupal\Core\Extension\ModuleHandler;
+use Drupal\Core\Plugin\Discovery\AnnotatedClassDiscovery;
+
+/**
+ * Base class for plugin managers.
+ */
+class DefaultPluginManager extends PluginManagerBase implements PluginManagerInterface {
+
+  /**
+   * The object that discovers plugins managed by this manager.
+   *
+   * @var \Drupal\Component\Plugin\Discovery\DiscoveryInterface
+   */
+  protected $discovery;
+
+  /**
+   * The object that instantiates plugins managed by this manager.
+   *
+   * @var \Drupal\Component\Plugin\Factory\FactoryInterface
+   */
+  protected $factory;
+
+  /**
+   * The object that returns the preconfigured plugin instance appropriate for
+   * a particular runtime condition.
+   *
+   * @var \Drupal\Component\Plugin\Mapper\MapperInterface
+   */
+  protected $mapper;
+
+  /**
+   * A set of defaults to be referenced by $this->processDefinition() if
+   * additional processing of plugins is necessary or helpful for development
+   * purposes.
+   *
+   * @var array
+   */
+  protected $defaults = array();
+
+  /**
+   * Cached definitions array.
+   *
+   * @var array
+   */
+  protected $definitions;
+
+  /**
+   * Cache backend instance.
+   *
+   * @var \Drupal\Core\Cache\CacheBackendInterface $cache
+   */
+  protected $cache;
+
+  /**
+   * Provided cache key prefix.
+   *
+   * @var string
+   */
+  protected $cacheKeyPrefix;
+
+  /**
+   * Actually used cache key with the language code appended.
+   *
+   * @var string
+   */
+  protected $cacheKey;
+
+  /**
+   * Name of the alter hook if one should be invoked.
+   *
+   * @var string
+   */
+  protected $alterHook;
+
+  /**
+   * The module that creates this plugin type.
+   * @var string
+   */
+  protected $owner;
+
+  /**
+   * The plugin type name.
+   *
+   * @var string
+   */
+  protected $type;
+
+  /**
+   * The module handler to invoke the alter hook.
+   *
+   * @var \Drupal\Core\Extension\ModuleHandler
+   */
+  protected $moduleHandler;
+
+  /**
+   * Constructs a \Drupal\Core\Plugin\DrupalPluginManagerBase object.
+   *
+   * Provides a Drupal ready plugin manager base class that implements caching
+   * appropriately and simplifies developer experience for creating new plugin
+   * managers.
+   *
+   * @param string $owner
+   *   The module that creates this plugin type.
+   * @param string $type
+   *   The plugin type name.
+   * @param array $namespaces
+   *   An array of paths keyed by it's corresponding namespaces.
+   */
+  public function __construct($owner, $type, array $namespaces) {
+    $this->owner = $owner;
+    $this->type = $type;
+    $this->discovery = new AnnotatedClassDiscovery($owner, $type, $namespaces);
+    $this->discovery = new DerivativeDiscoveryDecorator($this->discovery);
+
+    $this->factory = new DefaultFactory($this->discovery);
+  }
+
+  /**
+   * Sets the cache backend that should be used.
+   *
+   * Plugin definitions are cached used the cache backend if one is provided.
+   *
+   * @param \Drupal\Core\Cache\CacheBackendInterface $cache
+   *   Cache backend instance to use.
+   * @param type $cache_key_prefix
+   *   Cache key prefix to use, the language code will be appended automatically.
+   */
+  public function setCache(CacheBackendInterface $cache, $cache_key_prefix) {
+    $this->cache = $cache;
+    $this->cacheKeyPrefix = $cache_key_prefix;
+    $this->cacheKey = $cache_key_prefix . ':' . language(LANGUAGE_TYPE_INTERFACE)->langcode;
+  }
+
+  /**
+   * Set the alter hook name that should be used if needed.
+   *
+   * @param \Drupal\Core\Extension\ModuleHandler $module_handler
+   *   The module handler to invoke the alter hook with.
+   * @param string $alter_hook
+   *   (optional) Name of the alter hook. Defaults to $owner_$type if not given.
+   */
+  public function setAlterHook(ModuleHandler $module_handler, $alter_hook = NULL) {
+    $this->moduleHandler = $module_handler;
+    $this->alterHook = $alter_hook ? $alter_hook : $this->owner . '_' . $this->type;
+  }
+
+  /**
+   * Implements Drupal\Component\Plugin\PluginManagerInterface::createInstance().
+   */
+  public function createInstance($plugin_id, array $configuration = array()) {
+    return $this->factory->createInstance($plugin_id, $configuration);
+  }
+
+  /**
+   * Implements Drupal\Component\Plugin\PluginManagerInterface::getInstance().
+   */
+  public function getInstance(array $options) {
+    if (!empty($this->mapper)) {
+      return $this->mapper->getInstance($options);
+    }
+  }
+
+  /**
+   * Performs extra processing on plugin definitions.
+   *
+   * By default we add defaults for the type to the definition. If a type has
+   * additional processing logic they can do that by replacing or extending the
+   * method.
+   */
+  public function processDefinition(&$definition, $plugin_id) {
+    if ($this->defaults) {
+      $definition = NestedArray::mergeDeep($this->defaults, $definition);
+    }
+  }
+
+  /**
+   * Implements \Drupal\Component\Plugin\Discovery\CachedDiscoveryInterface::getDefinitions().
+   */
+  public function getDefinitions() {
+    $definitions = $this->getCachedDefinitions();
+    if (!isset($definitions)) {
+      $definitions = $this->discovery->getDefinitions();
+      foreach ($definitions as $plugin_id => &$definition) {
+        $this->processDefinition($definition, $plugin_id);
+      }
+      if ($this->alterHook) {
+        Drupal::service('module_handler')->alter($this->alterHook, $definitions);
+      }
+      $this->setCachedDefinitions($definitions);
+    }
+    return $definitions;
+  }
+
+  /**
+   * Implements \Drupal\Component\Plugin\Discovery\CachedDiscoveryInterface::clearCachedDefinitions().
+   */
+  public function clearCachedDefinitions() {
+    if ($this->cache) {
+      $cache_keys = array();
+      foreach (language_list() as $langcode => $language) {
+        $cache_keys[] = $this->cacheKeyPrefix . ':' .$langcode;
+      }
+      $this->cache->deleteMultiple($cache_keys);
+    }
+    $this->definitions = NULL;
+  }
+
+  /**
+   * Returns the cached plugin definitions of the decorated discovery class.
+   *
+   * @return mixed
+   *   On success this will return an array of plugin definitions. On failure
+   *   this should return NULL, indicating to other methods that this has not
+   *   yet been defined. Success with no values should return as an empty array
+   *   and would actually be returned by the getDefinitions() method.
+   */
+  protected function getCachedDefinitions() {
+    if (!isset($this->definitions) && $this->cache && $cache = $this->cache->get($this->cacheKey)) {
+      $this->definitions = $cache->data;
+    }
+    return $this->definitions;
+  }
+
+  /**
+   * Sets a cache of plugin definitions for the decorated discovery class.
+   *
+   * @param array $definitions
+   *   List of definitions to store in cache.
+   */
+  protected function setCachedDefinitions($definitions) {
+    if ($this->cache) {
+      $this->cache->set($this->cacheKey, $definitions, $this->cacheExpire, $this->cacheTags);
+    }
+    $this->definitions = $definitions;
+  }
+
+}
diff --git a/core/modules/block/lib/Drupal/block/BlockBundle.php b/core/modules/block/lib/Drupal/block/BlockBundle.php
index 71dfd33..f925b39 100644
--- a/core/modules/block/lib/Drupal/block/BlockBundle.php
+++ b/core/modules/block/lib/Drupal/block/BlockBundle.php
@@ -8,6 +8,7 @@
 namespace Drupal\Block;
 
 use Symfony\Component\DependencyInjection\ContainerBuilder;
+use Symfony\Component\DependencyInjection\Reference;
 use Symfony\Component\HttpKernel\Bundle\Bundle;
 
 /**
@@ -19,9 +20,19 @@ class BlockBundle extends Bundle {
    * Overrides \Symfony\Component\HttpKernel\Bundle\Bundle::build().
    */
   public function build(ContainerBuilder $container) {
-    // Register the BlockManager class with the dependency injection container.
+    $container
+      ->register('cache.block', 'Drupal\Core\Cache\CacheBackendInterface')
+      ->setFactoryClass('Drupal\Core\Cache\CacheFactory')
+      ->setFactoryMethod('get')
+      ->addArgument('block');
+
+    // Register the block manager with the dependency injection container.
     $container->register('plugin.manager.block', 'Drupal\block\Plugin\Type\BlockManager')
-      ->addArgument('%container.namespaces%');
+      ->addArgument('block')
+      ->addArgument('block')
+      ->addArgument('%container.namespaces%')
+      ->addMethodCall('setAlterHook', array(new Reference('module_handler'), 'block'))
+      ->addMethodCall('setCache', array(new Reference('cache.block'), 'block_plugins'));
   }
 
 }
diff --git a/core/modules/block/lib/Drupal/block/Plugin/Type/BlockManager.php b/core/modules/block/lib/Drupal/block/Plugin/Type/BlockManager.php
index d5dedb9..cf2b8ef 100644
--- a/core/modules/block/lib/Drupal/block/Plugin/Type/BlockManager.php
+++ b/core/modules/block/lib/Drupal/block/Plugin/Type/BlockManager.php
@@ -6,14 +6,9 @@
 
 namespace Drupal\block\Plugin\Type;
 
-use Drupal\Component\Plugin\PluginManagerBase;
-use Drupal\Component\Plugin\Discovery\DerivativeDiscoveryDecorator;
-use Drupal\Core\Cache\CacheBackendInterface;
-use Drupal\Core\Plugin\Discovery\AnnotatedClassDiscovery;
-use Drupal\Core\Plugin\Discovery\AlterDecorator;
-use Drupal\Core\Plugin\Discovery\CacheDecorator;
-use Drupal\Component\Plugin\Factory\DefaultFactory;
 use Drupal\block\Plugin\Core\Entity\Block;
+use Drupal\Component\Plugin\Factory\DefaultFactory;
+use Drupal\Core\Plugin\DefaultPluginManager;
 
 /**
  * Manages discovery and instantiation of block plugins.
@@ -22,20 +17,7 @@
  *
  * @see \Drupal\block\BlockInterface
  */
-class BlockManager extends PluginManagerBase {
-
-  /**
-   * Constructs a new \Drupal\block\Plugin\Type\BlockManager object.
-   *
-   * @param array $namespaces
-   *   An array of paths keyed by it's corresponding namespaces.
-   */
-  public function __construct(array $namespaces) {
-    $this->discovery = new AnnotatedClassDiscovery('block', 'block', $namespaces);
-    $this->discovery = new DerivativeDiscoveryDecorator($this->discovery);
-    $this->discovery = new AlterDecorator($this->discovery, 'block');
-    $this->discovery = new CacheDecorator($this->discovery, 'block_plugins:' . language(LANGUAGE_TYPE_INTERFACE)->langcode, 'cache_block', CacheBackendInterface::CACHE_PERMANENT, array('block'));
-  }
+class BlockManager extends DefaultPluginManager {
 
   /**
    * Overrides \Drupal\Component\Plugin\PluginManagerBase::createInstance().
