diff --git a/core/core.services.yml b/core/core.services.yml
index 55d5b34..55d79e1 100644
--- a/core/core.services.yml
+++ b/core/core.services.yml
@@ -153,7 +153,7 @@ services:
     arguments: ['@container.namespaces', '@service_container']
   plugin.manager.archiver:
     class: Drupal\Core\Archiver\ArchiverManager
-    arguments: ['@container.namespaces']
+    arguments: ['@container.namespaces', '@cache.cache', '@language_manager', '@module_handler']
   request:
     class: Symfony\Component\HttpFoundation\Request
   event_dispatcher:
@@ -178,7 +178,7 @@ services:
       - [setValidationConstraintManager, ['@validation.constraint']]
   validation.constraint:
     class: Drupal\Core\Validation\ConstraintManager
-    arguments: ['@container.namespaces']
+    arguments: ['@container.namespaces', '@cache.cache', '@language_manager', '@module_handler']
   lock:
     class: Drupal\Core\Lock\DatabaseLockBackend
   user.tempstore:
@@ -403,7 +403,7 @@ services:
     arguments: ['@database', '@request']
   plugin.manager.condition:
     class: Drupal\Core\Condition\ConditionManager
-    arguments: ['@container.namespaces']
+    arguments: ['@container.namespaces', '@cache.cache', '@language_manager', '@module_handler']
   kernel_destruct_subscriber:
     class: Drupal\Core\EventSubscriber\KernelDestructionSubscriber
     tags:
@@ -416,7 +416,7 @@ services:
       - { name: event_subscriber }
   image.toolkit.manager:
     class: Drupal\system\Plugin\ImageToolkitManager
-    arguments: ['@container.namespaces']
+    arguments: ['@container.namespaces', '@cache.cache', '@language_manager']
   image.toolkit:
     class: Drupal\system\Plugin\ImageToolkitInterface
     factory_method: getDefaultToolkit
diff --git a/core/lib/Drupal/Core/Archiver/ArchiverManager.php b/core/lib/Drupal/Core/Archiver/ArchiverManager.php
index f94869f..11ec29b 100644
--- a/core/lib/Drupal/Core/Archiver/ArchiverManager.php
+++ b/core/lib/Drupal/Core/Archiver/ArchiverManager.php
@@ -7,15 +7,15 @@
 namespace Drupal\Core\Archiver;
 
 use Drupal\Component\Plugin\Factory\DefaultFactory;
-use Drupal\Component\Plugin\PluginManagerBase;
-use Drupal\Core\Plugin\Discovery\AlterDecorator;
-use Drupal\Core\Plugin\Discovery\AnnotatedClassDiscovery;
-use Drupal\Core\Plugin\Discovery\CacheDecorator;
+use Drupal\Core\Cache\CacheBackendInterface;
+use Drupal\Core\Extension\ModuleHandlerInterface;
+use Drupal\Core\Language\LanguageManager;
+use Drupal\Core\Plugin\DefaultPluginManager;
 
 /**
  * Archiver plugin manager.
  */
-class ArchiverManager extends PluginManagerBase {
+class ArchiverManager extends DefaultPluginManager {
 
   /**
    * Constructs a ArchiverManager object.
@@ -23,11 +23,17 @@ class ArchiverManager extends PluginManagerBase {
    * @param \Traversable $namespaces
    *   An object that implements \Traversable which contains the root paths
    *   keyed by the corresponding namespace to look for plugin implementations,
+   * @param \Drupal\Core\Cache\CacheBackendInterface $cache
+   *   Cache backend instance to use.
+   * @param \Drupal\Core\Language\LanguageManager
+   *   The language manager.
+   * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
+   *   The module handler to invoke the alter hook with.
    */
-  public function __construct(\Traversable $namespaces) {
-    $this->discovery = new AnnotatedClassDiscovery('Archiver', $namespaces);
-    $this->discovery = new AlterDecorator($this->discovery, 'archiver_info');
-    $this->discovery = new CacheDecorator($this->discovery, 'archiver_info');
+  public function __construct(\Traversable $namespaces, CacheBackendInterface $cache, LanguageManager $language_manager, ModuleHandlerInterface $module_handler) {
+    parent::__construct('Archiver', $namespaces);
+    $this->alterInfo($module_handler, 'archiver_info');
+    $this->setCache($cache, $language_manager, 'archiver_info');
   }
 
   /**
diff --git a/core/lib/Drupal/Core/Condition/ConditionManager.php b/core/lib/Drupal/Core/Condition/ConditionManager.php
index e973132..ead3a9c 100644
--- a/core/lib/Drupal/Core/Condition/ConditionManager.php
+++ b/core/lib/Drupal/Core/Condition/ConditionManager.php
@@ -7,35 +7,35 @@
 
 namespace Drupal\Core\Condition;
 
-use Drupal\Component\Plugin\PluginManagerBase;
+use Drupal\Core\Cache\CacheBackendInterface;
 use Drupal\Core\Executable\ExecutableManagerInterface;
 use Drupal\Core\Executable\ExecutableInterface;
-use Drupal\Component\Plugin\Factory\DefaultFactory;
-use Drupal\Component\Plugin\Discovery\DerivativeDiscoveryDecorator;
-use Drupal\Core\Language\Language;
-use Drupal\Core\Plugin\Discovery\AlterDecorator;
-use Drupal\Core\Plugin\Discovery\AnnotatedClassDiscovery;
-use Drupal\Core\Plugin\Discovery\CacheDecorator;
+use Drupal\Core\Extension\ModuleHandlerInterface;
+use Drupal\Core\Language\LanguageManager;
+use Drupal\Core\Plugin\DefaultPluginManager;
 
 /**
  * A plugin manager for condition plugins.
  */
-class ConditionManager extends PluginManagerBase implements ExecutableManagerInterface {
+class ConditionManager extends DefaultPluginManager implements ExecutableManagerInterface {
 
   /**
-   * Constructs aa ConditionManager object.
+   * Constructs a ConditionManager object.
    *
    * @param \Traversable $namespaces
    *   An object that implements \Traversable which contains the root paths
    *   keyed by the corresponding namespace to look for plugin implementations,
+   * @param \Drupal\Core\Cache\CacheBackendInterface $cache
+   *   Cache backend instance to use.
+   * @param \Drupal\Core\Language\LanguageManager
+   *   The language manager.
+   * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
+   *   The module handler to invoke the alter hook with.
    */
-  public function __construct(\Traversable $namespaces) {
-    $this->discovery = new AnnotatedClassDiscovery('Condition', $namespaces);
-    $this->discovery = new DerivativeDiscoveryDecorator($this->discovery);
-    $this->discovery = new AlterDecorator($this->discovery, 'condition_info');
-    $this->discovery = new CacheDecorator($this->discovery, 'condition:' . language(Language::TYPE_INTERFACE)->langcode);
-
-    $this->factory = new DefaultFactory($this);
+  public function __construct(\Traversable $namespaces, CacheBackendInterface $cache, LanguageManager $language_manager, ModuleHandlerInterface $module_handler) {
+    parent::__construct('Condition', $namespaces);
+    $this->alterInfo($module_handler, 'condition_info');
+    $this->setCache($cache, $language_manager, 'condition');
   }
 
   /**
diff --git a/core/lib/Drupal/Core/Plugin/DefaultPluginManager.php b/core/lib/Drupal/Core/Plugin/DefaultPluginManager.php
new file mode 100644
index 0000000..9b08432
--- /dev/null
+++ b/core/lib/Drupal/Core/Plugin/DefaultPluginManager.php
@@ -0,0 +1,226 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\Plugin\DefaultPluginManager
+ */
+
+namespace Drupal\Core\Plugin;
+
+use Drupal\Component\Plugin\Discovery\CachedDiscoveryInterface;
+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\ModuleHandlerInterface;
+use Drupal\Core\Language\LanguageManager;
+use Drupal\Core\Language\Language;
+use Drupal\Core\Plugin\Discovery\AnnotatedClassDiscovery;
+
+/**
+ * Base class for plugin managers.
+ */
+abstract class DefaultPluginManager extends PluginManagerBase implements PluginManagerInterface, CachedDiscoveryInterface {
+
+  /**
+   * 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 plugin's subdirectory, for example views/filter.
+   *
+   * @var string
+   */
+  protected $subdir;
+
+  /**
+   * The module handler to invoke the alter hook.
+   *
+   * @var \Drupal\Core\Extension\ModuleHandlerInterface
+   */
+  protected $moduleHandler;
+
+  /**
+   * The language manager.
+   *
+   * @var \Drupal\Core\Language\LanguageManager
+   */
+  protected $languageManager;
+
+  /**
+   * Creates the discovery object.
+   *
+   * @param string $subdir
+   *   The plugin's subdirectory, for example views/filter.
+   * @param \Traversable $namespaces
+   *   An object that implements \Traversable which contains the root paths
+   *   keyed by the corresponding namespace to look for plugin implementations
+   * @param array $annotation_namespaces
+   *   (optional) The namespaces of classes that can be used as annotations.
+   *   Defaults to an empty array.
+   * @param string $plugin_definition_annotation_name
+   *   (optional) The name of the annotation that contains the plugin definition.
+   *   Defaults to 'Drupal\Component\Annotation\Plugin'.
+   */
+  public function __construct($subdir, \Traversable $namespaces, $annotation_namespaces = array(), $plugin_definition_annotation_name = 'Drupal\Component\Annotation\Plugin') {
+    $this->subdir = $subdir;
+    $this->discovery = new AnnotatedClassDiscovery($subdir, $namespaces, $annotation_namespaces, $plugin_definition_annotation_name);
+    $this->discovery = new DerivativeDiscoveryDecorator($this->discovery);
+    $this->factory = new DefaultFactory($this);
+  }
+
+  /**
+   * Initialize the cache backend.
+   *
+   * Plugin definitions are cached using the provided cache backend. The
+   * interface languge is added as a suffix to the cache key.
+   *
+   * @param \Drupal\Core\Cache\CacheBackendInterface $cache
+   *   Cache backend instance to use.
+   * @param \Drupal\Core\Language\LanguageManager
+   *   The language manager.
+   * @param type $cache_key_prefix
+   *   Cache key prefix to use, the language code will be appended
+   *   automatically.
+   */
+  public function setCache(CacheBackendInterface $cache, LanguageManager $language_manager, $cache_key_prefix) {
+    $this->languageManager = $language_manager;
+    $this->cache = $cache;
+    $this->cacheKeyPrefix = $cache_key_prefix;
+    $this->cacheKey = $cache_key_prefix . ':' . $language_manager->getLanguage(Language::TYPE_INTERFACE)->langcode;
+  }
+
+  /**
+   * Initializes the alter hook.
+   *
+   * @param \Drupal\Core\Extension\ModuleHandler $module_handler
+   *   The module handler to invoke the alter hook with.
+   * @param string $alter_hook
+   *   Name of the alter hook.
+   */
+  protected function alterInfo(ModuleHandlerInterface $module_handler, $alter_hook) {
+    $this->moduleHandler = $module_handler;
+    $this->alterHook = $alter_hook;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getDefinition($plugin_id) {
+    // Fetch definitions if they're not loaded yet.
+    if (!isset($this->definitions)) {
+      $this->getDefinitions();
+    }
+    // Avoid using a ternary that would create a copy of the array.
+    if (isset($this->definitions[$plugin_id])) {
+      return $this->definitions[$plugin_id];
+    }
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getDefinitions() {
+    $definitions = $this->getCachedDefinitions();
+    if (!isset($definitions)) {
+      $definitions = $this->findDefinitions();
+      $this->setCachedDefinitions($definitions);
+    }
+    return $definitions;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function clearCachedDefinitions() {
+    if ($this->cache) {
+      $cache_keys = array();
+      // @todo: Use $this->languageManager->languageList() after http://drupal.org/node/1862202 is in.
+      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 array|NULL
+   *   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->definitions = $definitions;
+  }
+
+  /**
+   * Finds plugin definitions.
+   *
+   * @return array
+   *   List of definitions to store in cache.
+   */
+  protected function findDefinitions() {
+    $definitions = $this->discovery->getDefinitions();
+    foreach ($definitions as $plugin_id => &$definition) {
+      $this->processDefinition($definition, $plugin_id);
+    }
+    if ($this->alterHook) {
+      $this->moduleHandler->alter($this->alterHook, $definitions);
+    }
+    return $definitions;
+  }
+
+}
diff --git a/core/lib/Drupal/Core/Validation/ConstraintManager.php b/core/lib/Drupal/Core/Validation/ConstraintManager.php
index da84d55..ee902d4 100644
--- a/core/lib/Drupal/Core/Validation/ConstraintManager.php
+++ b/core/lib/Drupal/Core/Validation/ConstraintManager.php
@@ -7,15 +7,11 @@
 
 namespace Drupal\Core\Validation;
 
-use Drupal\Component\Plugin\Factory\DefaultFactory;
-use Drupal\Component\Plugin\PluginManagerBase;
 use Drupal\Component\Plugin\Discovery\StaticDiscoveryDecorator;
-use Drupal\Component\Plugin\Discovery\DerivativeDiscoveryDecorator;
-use Drupal\Component\Plugin\Discovery\ProcessDecorator;
-use Drupal\Core\Language\Language;
-use Drupal\Core\Plugin\Discovery\AlterDecorator;
-use Drupal\Core\Plugin\Discovery\AnnotatedClassDiscovery;
-use Drupal\Core\Plugin\Discovery\CacheDecorator;
+use Drupal\Core\Cache\CacheBackendInterface;
+use Drupal\Core\Extension\ModuleHandler;
+use Drupal\Core\Language\LanguageManager;
+use Drupal\Core\Plugin\DefaultPluginManager;
 
 /**
  * Constraint plugin manager.
@@ -35,7 +31,7 @@
  * types FALSE may be specified. The key defaults to an empty array, i.e. no
  * types are supported.
  */
-class ConstraintManager extends PluginManagerBase {
+class ConstraintManager extends DefaultPluginManager {
 
   /**
    * Overrides \Drupal\Component\Plugin\PluginManagerBase::__construct().
@@ -43,16 +39,18 @@ class ConstraintManager extends PluginManagerBase {
    * @param \Traversable $namespaces
    *   An object that implements \Traversable which contains the root paths
    *   keyed by the corresponding namespace to look for plugin implementations,
+   * @param \Drupal\Core\Cache\CacheBackendInterface $cache
+   *   Cache backend instance to use.
+   * @param \Drupal\Core\Language\LanguageManager
+   *   The language manager.
+   * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
+   *   The module handler to invoke the alter hook with.
    */
-  public function __construct(\Traversable $namespaces) {
-    $this->discovery = new AnnotatedClassDiscovery('Validation/Constraint', $namespaces);
+  public function __construct(\Traversable $namespaces, CacheBackendInterface $cache, LanguageManager $language_manager, ModuleHandler $module_handler) {
+    parent::__construct('Validation/Constraint', $namespaces);
     $this->discovery = new StaticDiscoveryDecorator($this->discovery, array($this, 'registerDefinitions'));
-    $this->discovery = new DerivativeDiscoveryDecorator($this->discovery);
-    $this->discovery = new ProcessDecorator($this->discovery, array($this, 'processDefinition'));
-    $this->discovery = new AlterDecorator($this->discovery, 'validation_constraint');
-    $this->discovery = new CacheDecorator($this->discovery, 'validation_constraints:' . language(Language::TYPE_INTERFACE)->langcode);
-
-    $this->factory = new DefaultFactory($this);
+    $this->alterInfo($module_handler, 'validation_constraint');
+    $this->setCache($cache, $language_manager, 'validation_constraint');
   }
 
   /**
diff --git a/core/modules/block/block.services.yml b/core/modules/block/block.services.yml
index 745bf66..6e87ce2 100644
--- a/core/modules/block/block.services.yml
+++ b/core/modules/block/block.services.yml
@@ -1,7 +1,7 @@
 services:
   plugin.manager.block:
     class: Drupal\block\Plugin\Type\BlockManager
-    arguments: ['@container.namespaces']
+    arguments: ['@container.namespaces', '@cache.block', '@language_manager', '@module_handler']
   cache.block:
     class: Drupal\Core\Cache\CacheBackendInterface
     tags:
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 012bf10..4932daf 100644
--- a/core/modules/block/lib/Drupal/block/Plugin/Type/BlockManager.php
+++ b/core/modules/block/lib/Drupal/block/Plugin/Type/BlockManager.php
@@ -6,15 +6,10 @@
 
 namespace Drupal\block\Plugin\Type;
 
-use Drupal\Component\Plugin\PluginManagerBase;
-use Drupal\Component\Plugin\Discovery\DerivativeDiscoveryDecorator;
 use Drupal\Core\Cache\CacheBackendInterface;
-use Drupal\Core\Language\Language;
-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\Core\Extension\ModuleHandlerInterface;
+use Drupal\Core\Language\LanguageManager;
+use Drupal\Core\Plugin\DefaultPluginManager;
 /**
  * Manages discovery and instantiation of block plugins.
  *
@@ -22,7 +17,7 @@
  *
  * @see \Drupal\block\BlockPluginInterface
  */
-class BlockManager extends PluginManagerBase {
+class BlockManager extends DefaultPluginManager {
 
   /**
    * Constructs a new \Drupal\block\Plugin\Type\BlockManager object.
@@ -30,14 +25,16 @@ class BlockManager extends PluginManagerBase {
    * @param \Traversable $namespaces
    *   An object that implements \Traversable which contains the root paths
    *   keyed by the corresponding namespace to look for plugin implementations,
+   * @param \Drupal\Core\Cache\CacheBackendInterface $cache
+   *   Cache backend instance to use.
+   * @param \Drupal\Core\Language\LanguageManager
+   *   The language manager.
+   * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
+   *   The module handler to invoke the alter hook with.
    */
-  public function __construct(\Traversable $namespaces) {
-    $this->discovery = new AnnotatedClassDiscovery('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, 'block', CacheBackendInterface::CACHE_PERMANENT, array('block'));
-
-    $this->factory = new DefaultFactory($this->discovery);
+  public function __construct(\Traversable $namespaces, CacheBackendInterface $cache, LanguageManager $language_manager, ModuleHandlerInterface $module_handler) {
+    parent::__construct('Block', $namespaces);
+    $this->alterInfo($module_handler, 'block');
+    $this->setCache($cache, $language_manager, 'block_plugins');
   }
-
 }
diff --git a/core/modules/system/lib/Drupal/system/Plugin/ImageToolkitManager.php b/core/modules/system/lib/Drupal/system/Plugin/ImageToolkitManager.php
index dc5fb34..47872f9 100644
--- a/core/modules/system/lib/Drupal/system/Plugin/ImageToolkitManager.php
+++ b/core/modules/system/lib/Drupal/system/Plugin/ImageToolkitManager.php
@@ -7,14 +7,14 @@
 
 namespace Drupal\system\Plugin;
 
-use Drupal\Component\Plugin\Factory\DefaultFactory;
-use Drupal\Component\Plugin\PluginManagerBase;
-use Drupal\Core\Plugin\Discovery\AnnotatedClassDiscovery;
+use Drupal\Core\Cache\CacheBackendInterface;
+use Drupal\Core\Language\LanguageManager;
+use Drupal\Core\Plugin\DefaultPluginManager;
 
 /**
  * Manages toolkit plugins.
  */
-class ImageToolkitManager extends PluginManagerBase {
+class ImageToolkitManager extends DefaultPluginManager {
 
   /**
    * Constructs the ImageToolkitManager object.
@@ -22,10 +22,12 @@ class ImageToolkitManager extends PluginManagerBase {
    * @param \Traversable $namespaces
    *   An object that implements \Traversable which contains the root paths
    *   keyed by the corresponding namespace to look for plugin implementations,
+   * @param \Drupal\Core\Cache\CacheBackendInterface $cache
+   *   Cache backend instance to use.
    */
-  public function __construct(\Traversable $namespaces) {
-    $this->discovery = new AnnotatedClassDiscovery('ImageToolkit', $namespaces);
-    $this->factory = new DefaultFactory($this->discovery);
+  public function __construct(\Traversable $namespaces, CacheBackendInterface $cache, LanguageManager $language_manager) {
+    parent::__construct('ImageToolkit', $namespaces);
+    $this->setCache($cache, $language_manager, 'image_toolkit');
   }
 
   /**
diff --git a/core/modules/system/lib/Drupal/system/Tests/Image/ToolkitGdTest.php b/core/modules/system/lib/Drupal/system/Tests/Image/ToolkitGdTest.php
index 6f4075d..624dc79 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Image/ToolkitGdTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Image/ToolkitGdTest.php
@@ -215,7 +215,7 @@ function testManipulations() {
       );
     }
 
-    $manager = new ImageToolkitManager($this->container->get('container.namespaces'));
+    $manager = new ImageToolkitManager($this->container->get('container.namespaces'), $this->container->get('cache.cache'), $this->container->get('language_manager'));
     foreach ($files as $file) {
       foreach ($operations as $op => $values) {
         // Load up a fresh image.
diff --git a/core/modules/system/lib/Drupal/system/Tests/Image/ToolkitTest.php b/core/modules/system/lib/Drupal/system/Tests/Image/ToolkitTest.php
index d0d64a3..24e10b0 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Image/ToolkitTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Image/ToolkitTest.php
@@ -26,7 +26,7 @@ public static function getInfo() {
    * available toolkits.
    */
   function testGetAvailableToolkits() {
-    $manager = new ImageToolkitManager($this->container->get('container.namespaces'));
+    $manager = new ImageToolkitManager($this->container->get('container.namespaces'), $this->container->get('cache.cache'), $this->container->get('language_manager'));
     $toolkits = $manager->getAvailableToolkits();
     $this->assertTrue(isset($toolkits['test']), 'The working toolkit was returned.');
     $this->assertFalse(isset($toolkits['broken']), 'The toolkit marked unavailable was not returned');
diff --git a/core/modules/system/lib/Drupal/system/Tests/Image/ToolkitTestBase.php b/core/modules/system/lib/Drupal/system/Tests/Image/ToolkitTestBase.php
index 260b2da..648aca8 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Image/ToolkitTestBase.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Image/ToolkitTestBase.php
@@ -31,7 +31,7 @@ function setUp() {
     parent::setUp();
 
     // Use the image_test.module's test toolkit.
-    $manager = new ImageToolkitManager($this->container->get('container.namespaces'));
+    $manager = new ImageToolkitManager($this->container->get('container.namespaces'), $this->container->get('cache.cache'), $this->container->get('language_manager'));
     $this->toolkit = $manager->createInstance('test');
 
     // Pick a file for testing.
diff --git a/core/modules/system/tests/modules/condition_test/lib/Drupal/condition_test/FormController.php b/core/modules/system/tests/modules/condition_test/lib/Drupal/condition_test/FormController.php
index b1012c2..3e42efc 100644
--- a/core/modules/system/tests/modules/condition_test/lib/Drupal/condition_test/FormController.php
+++ b/core/modules/system/tests/modules/condition_test/lib/Drupal/condition_test/FormController.php
@@ -33,7 +33,7 @@ public function getFormID() {
    * Constructs a \Drupal\condition_test\FormController object.
    */
   public function __construct() {
-    $manager = new ConditionManager(\Drupal::service('container.namespaces'));
+    $manager = new ConditionManager(\Drupal::service('container.namespaces'), \Drupal::cache('cache'), \Drupal::service('language_manager'), \Drupal::moduleHandler());
     $this->condition = $manager->createInstance('node_type');
   }
 
diff --git a/core/modules/system/tests/modules/plugin_test/lib/Drupal/plugin_test/Plugin/DefaultsTestPluginManager.php b/core/modules/system/tests/modules/plugin_test/lib/Drupal/plugin_test/Plugin/DefaultsTestPluginManager.php
index f62fcc9..96693c2 100644
--- a/core/modules/system/tests/modules/plugin_test/lib/Drupal/plugin_test/Plugin/DefaultsTestPluginManager.php
+++ b/core/modules/system/tests/modules/plugin_test/lib/Drupal/plugin_test/Plugin/DefaultsTestPluginManager.php
@@ -7,15 +7,14 @@
 
 namespace Drupal\plugin_test\Plugin;
 
-use Drupal\Component\Plugin\PluginManagerBase;
 use Drupal\Component\Plugin\Discovery\StaticDiscovery;
-use Drupal\Component\Plugin\Discovery\ProcessDecorator;
 use Drupal\Component\Plugin\Factory\DefaultFactory;
+use Drupal\Core\Plugin\DefaultPluginManager;
 
 /**
  * Defines a plugin manager used by Plugin API unit tests.
  */
-class DefaultsTestPluginManager extends PluginManagerBase {
+class DefaultsTestPluginManager extends DefaultPluginManager {
 
   public function __construct() {
     // Create the object that can be used to return definitions for all the
@@ -23,7 +22,6 @@ public function __construct() {
     // discovery implementation, but StaticDiscovery lets us add some simple
     // mock plugins for unit testing.
     $this->discovery = new StaticDiscovery();
-    $this->discovery = new ProcessDecorator($this->discovery, array($this, 'ProcessDefinition'));
     $this->factory = new DefaultFactory($this->discovery);
 
     // Specify default values.
diff --git a/core/tests/Drupal/Tests/Core/Plugin/DefaultPluginManagerTest.php b/core/tests/Drupal/Tests/Core/Plugin/DefaultPluginManagerTest.php
new file mode 100644
index 0000000..07de26b
--- /dev/null
+++ b/core/tests/Drupal/Tests/Core/Plugin/DefaultPluginManagerTest.php
@@ -0,0 +1,159 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\Plugin\DefaultPluginManagerTest.
+ */
+
+namespace Drupal\Tests\Core\Plugin;
+
+use Drupal\Core\Language\Language;
+use Drupal\Tests\UnitTestCase;
+
+/**
+ * Tests the DefaultPluginManager.
+ *
+ * @group Plugin
+ */
+class DefaultPluginManagerTest extends UnitTestCase {
+
+  /**
+   * The expected plugin definitions.
+   *
+   * @var array
+   */
+  protected $expectedDefinitions;
+
+  /**
+   * The namespaces to look for plugin definitions.
+   *
+   * @var \Traversable
+   */
+  protected $namespaces;
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function getInfo() {
+    return array(
+      'name' => 'Default Plugin Manager',
+      'description' => 'Tests the DefaultPluginManager class.',
+      'group' => 'Plugin',
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp() {
+    $this->expectedDefinitions = array(
+      'apple' => array(
+        'id' => 'apple',
+        'label' => 'Apple',
+        'color' => 'green',
+        'class' => 'Drupal\plugin_test\Plugin\plugin_test\fruit\Apple',
+      ),
+      'banana' => array(
+        'id' => 'banana',
+        'label' => 'Banana',
+        'color' => 'yellow',
+        'uses' => array(
+          'bread' => 'Banana bread',
+        ),
+        'class' => 'Drupal\plugin_test\Plugin\plugin_test\fruit\Banana',
+      ),
+    );
+
+    $this->namespaces = new \ArrayObject(array('Drupal\plugin_test' => DRUPAL_ROOT . '/core/modules/system/tests/modules/plugin_test/lib'));
+  }
+
+  /**
+   * Tests the plugin manager with no cache and altering.
+   */
+  public function testDefaultPluginManager() {
+    $plugin_manager = new TestPluginManager($this->namespaces, $this->expectedDefinitions);
+    $this->assertEquals($this->expectedDefinitions, $plugin_manager->getDefinitions());
+    $this->assertEquals($this->expectedDefinitions['banana'], $plugin_manager->getDefinition('banana'));
+  }
+
+  /**
+   * Tests the plugin manager with no cache and altering.
+   */
+  public function testDefaultPluginManagerWithAlter() {
+    $module_handler = $this->getMock('Drupal\Core\Extension\ModuleHandler');
+
+    // Configure the stub.
+    $alter_hook_name = $this->randomName();
+    $module_handler->expects($this->once())
+      ->method('alter')
+      ->with($this->equalTo($alter_hook_name), $this->equalTo($this->expectedDefinitions));
+
+    $plugin_manager = new TestPluginManager($this->namespaces, $this->expectedDefinitions, $module_handler, $alter_hook_name);
+
+    $this->assertEquals($this->expectedDefinitions, $plugin_manager->getDefinitions());
+    $this->assertEquals($this->expectedDefinitions['banana'], $plugin_manager->getDefinition('banana'));
+  }
+
+  /**
+   * Tests the plugin manager with caching and altering.
+   */
+  public function testDefaultPluginManagerWithEmptyCache() {
+    $cid = $this->randomName();
+    $cache_backend = $this->getMockBuilder('Drupal\Core\Cache\MemoryBackend')
+      ->disableOriginalConstructor()
+      ->getMock();
+    $cache_backend
+      ->expects($this->once())
+      ->method('get')
+      ->with($cid . ':en')
+      ->will($this->returnValue(FALSE));
+    $cache_backend
+      ->expects($this->once())
+      ->method('set')
+      ->with($cid . ':en', $this->expectedDefinitions);
+
+    $language = new Language(array('langcode' => 'en'));
+    $language_manager = $this->getMock('Drupal\Core\Language\LanguageManager');
+    $language_manager->expects($this->once())
+      ->method('getLanguage')
+      ->with(Language::TYPE_INTERFACE)
+      ->will($this->returnValue($language));
+
+    $plugin_manager = new TestPluginManager($this->namespaces, $this->expectedDefinitions);
+    $plugin_manager->setCache($cache_backend, $language_manager, $cid);
+
+    $this->assertEquals($this->expectedDefinitions, $plugin_manager->getDefinitions());
+    $this->assertEquals($this->expectedDefinitions['banana'], $plugin_manager->getDefinition('banana'));
+  }
+
+  /**
+   * Tests the plugin manager with caching and altering.
+   */
+  public function testDefaultPluginManagerWithFilledCache() {
+    $cid = $this->randomName();
+    $cache_backend = $this->getMockBuilder('Drupal\Core\Cache\MemoryBackend')
+      ->disableOriginalConstructor()
+      ->getMock();
+    $cache_backend
+      ->expects($this->once())
+      ->method('get')
+      ->with($cid . ':en')
+      ->will($this->returnValue((object) array('data' => $this->expectedDefinitions)));
+    $cache_backend
+      ->expects($this->never())
+      ->method('set');
+
+    $language = new Language(array('langcode' => 'en'));
+    $language_manager = $this->getMock('Drupal\Core\Language\LanguageManager');
+    $language_manager->expects($this->once())
+      ->method('getLanguage')
+      ->with(Language::TYPE_INTERFACE)
+      ->will($this->returnValue($language));
+
+    $plugin_manager = new TestPluginManager($this->namespaces, $this->expectedDefinitions);
+    $plugin_manager->setCache($cache_backend, $language_manager, $cid);
+
+    $this->assertEquals($this->expectedDefinitions, $plugin_manager->getDefinitions());
+  }
+
+}
diff --git a/core/tests/Drupal/Tests/Core/Plugin/TestPluginManager.php b/core/tests/Drupal/Tests/Core/Plugin/TestPluginManager.php
new file mode 100644
index 0000000..746adcf
--- /dev/null
+++ b/core/tests/Drupal/Tests/Core/Plugin/TestPluginManager.php
@@ -0,0 +1,47 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Tests\Plugin\Core\TestDefaultPluginManager.
+ */
+
+namespace Drupal\Tests\Core\Plugin;
+
+use Drupal\Component\Plugin\Discovery\StaticDiscovery;
+use Drupal\Core\Extension\ModuleHandlerInterface;
+use Drupal\Core\Plugin\DefaultPluginManager;
+
+/**
+ * A plugin manager for condition plugins.
+ */
+class TestPluginManager extends DefaultPluginManager {
+
+  /**
+   * Constructs aa ConditionManager object.
+   *
+   * @param \Traversable $namespaces
+   *   An object that implements \Traversable which contains the root paths
+   *   keyed by the corresponding namespace to look for plugin implementations,
+   * @param \Drupal\Core\Extension\ModuleHandler $module_handler
+   *   (optional) The module handler to invoke the alter hook with.
+   * @param string $alter_hook
+   *   (optional) Name of the alter hook.
+   */
+  public function __construct(\Traversable $namespaces, $definitions, ModuleHandlerInterface $module_handler = NULL, $alter_hook = NULL) {
+    // Create the object that can be used to return definitions for all the
+    // plugins available for this type. Most real plugin managers use a richer
+    // discovery implementation, but StaticDiscovery lets us add some simple
+    // mock plugins for unit testing.
+    $this->discovery = new StaticDiscovery();
+
+    // Add the static definitions.
+    foreach ($definitions as $key => $definition) {
+      $this->discovery->setDefinition($key, $definition);
+    }
+
+    if ($module_handler && $alter_hook) {
+      $this->alterInfo($module_handler, $alter_hook);
+    }
+  }
+
+}
