diff --git a/core/lib/Drupal/Component/Plugin/Discovery/DerivativeDiscoveryDecorator.php b/core/lib/Drupal/Component/Plugin/Discovery/DerivativeDiscoveryDecorator.php
index e245874..9402c87 100644
--- a/core/lib/Drupal/Component/Plugin/Discovery/DerivativeDiscoveryDecorator.php
+++ b/core/lib/Drupal/Component/Plugin/Discovery/DerivativeDiscoveryDecorator.php
@@ -13,7 +13,7 @@
  * Provides a decorator that allows the use of plugin derivatives for normal
  * implementations DiscoveryInterface.
  */
-class DerivativeDiscoveryDecorator implements DiscoveryInterface {
+class DerivativeDiscoveryDecorator extends DiscoveryBase implements DiscoveryInterface {
 
   protected $derivativeFetchers = array();
   protected $decorated;
diff --git a/core/lib/Drupal/Component/Plugin/Discovery/DiscoveryBase.php b/core/lib/Drupal/Component/Plugin/Discovery/DiscoveryBase.php
new file mode 100644
index 0000000..4cccb49
--- /dev/null
+++ b/core/lib/Drupal/Component/Plugin/Discovery/DiscoveryBase.php
@@ -0,0 +1,60 @@
+<?php
+
+namespace Drupal\Component\Plugin\Discovery;
+
+use Drupal\Component\Plugin\PluginManagerInterface;
+use Drupal\Core\Plugin\Discovery\AlterDecorator;
+
+abstract class DiscoveryBase implements DiscoveryInterface {
+
+  protected $manager;
+
+  /**
+   * The array of plugin definitions, keyed by plugin id.
+   *
+   * @var array
+   */
+  protected $definitions = array();
+
+  /**
+   * Implements DiscoveryInterface::getDefinition().
+   */
+  public function getDefinition($plugin_id) {
+    $definitions = $this->getDefinitions();
+    return isset($definitions[$plugin_id]) ? $definitions[$plugin_id] : NULL;
+  }
+
+  /**
+   * Implements DiscoveryInterface::getDefinitions().
+   */
+  public function getDefinitions() {
+    return $this->definitions;
+  }
+
+  /**
+   * Implements DiscoveryInterface::useDefaults().
+   */
+  public function useDefaults(PluginManagerInterface $manager) {
+    $this->manager = $manager;
+    return $this;
+  }
+
+  public function processDefaults() {
+    if (!empty($this->manager)) {
+      $definitions = $this->getDefinitions();
+      foreach ($definitions as $plugin_id => &$definition) {
+        $this->manager->processDefinition($definition, $plugin_id);
+      }
+      $this->definitions = $definitions;
+    }
+    elseif (!empty($this->decorated)) {
+      $this->decorated->processDefaults();
+    }
+  }
+
+  public function __call($method, $args) {
+    if (!empty($this->decorated)) {
+      return call_user_func_array(array($this->decorated, $method), $args);
+    }
+  }
+}
\ No newline at end of file
diff --git a/core/lib/Drupal/Component/Plugin/Discovery/DiscoveryInterface.php b/core/lib/Drupal/Component/Plugin/Discovery/DiscoveryInterface.php
index aaf4743..3e1a004 100644
--- a/core/lib/Drupal/Component/Plugin/Discovery/DiscoveryInterface.php
+++ b/core/lib/Drupal/Component/Plugin/Discovery/DiscoveryInterface.php
@@ -6,6 +6,7 @@
  */
 
 namespace Drupal\Component\Plugin\Discovery;
+use Drupal\Component\Plugin\PluginManagerInterface;
 
 /**
  * An interface defining the minimum requirements of building a plugin
@@ -33,4 +34,22 @@ public function getDefinition($plugin_id);
    */
   public function getDefinitions();
 
+  /**
+   * Allows for defaults processing within the discovery before the default
+   * processing that occurse in the PluginManager.
+   *
+   * @param PluginManagerInterface $manager
+   *   The Plugin Manager with the defaults on it.
+   *
+   * @return DiscoveryInterface object
+   *   Should return $this;
+   */
+  public function useDefaults(PluginManagerInterface $manager);
+
+  /**
+   * Processes the defaults that have been passed in useDefaults if any. This
+   * method will then save the resulting definitions into $this->definitions
+   * to prevent processing the same definitions twice.
+   */
+  public function processDefaults();
 }
diff --git a/core/lib/Drupal/Component/Plugin/Discovery/ProcessDecorator.php b/core/lib/Drupal/Component/Plugin/Discovery/ProcessDecorator.php
deleted file mode 100644
index bcb5cad..0000000
--- a/core/lib/Drupal/Component/Plugin/Discovery/ProcessDecorator.php
+++ /dev/null
@@ -1,77 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\Component\Plugin\Discovery\ProcessDecorator.
- */
-
-namespace Drupal\Component\Plugin\Discovery;
-
-/**
- * Allows custom processing of the discovered definition.
- *
- * Example use cases include adding in default values for a definition, or
- * providing a backwards compatibility layer for renamed definition properties.
- */
-class ProcessDecorator implements DiscoveryInterface {
-
-  /**
-   * The Discovery object being decorated.
-   *
-   * @var \Drupal\Component\Plugin\Discovery\DiscoveryInterface
-   */
-  protected $decorated;
-
-  /**
-   * The processor callback to run on each discovered definition.
-   *
-   * @var callable
-   */
-   protected $processCallback;
-
-  /**
-   * Constructs a \Drupal\Component\Plugin\Discovery\ProcessDecorator object.
-   *
-   * @param \Drupal\Component\Plugin\Discovery\DiscoveryInterface $decorated
-   *   The discovery object that is being decorated.
-   * @param callable $process_callback
-   *   The processor callback to run on each discovered definition. The
-   *   callback will be called with the following arguments:
-   *   - array $definition: the discovered definition, that the callback
-   *     should accept by reference and modify in place.
-   *   - string $plugin_id: the corresponding plugin_id.
-   */
-  public function __construct(DiscoveryInterface $decorated, $process_callback) {
-    $this->decorated = $decorated;
-    $this->processCallback = $process_callback;
-  }
-
-  /**
-   * Implements \Drupal\Component\Plugin\Discovery\DicoveryInterface::getDefinition().
-   */
-  public function getDefinition($plugin_id) {
-    $definitions = $this->getDefinitions();
-    if (isset($definitions[$plugin_id])) {
-      return $definitions[$plugin_id];
-    }
-  }
-
-  /**
-   * Implements \Drupal\Component\Plugin\Discovery\DicoveryInterface::getDefinitions().
-   */
-  public function getDefinitions() {
-    $definitions = $this->decorated->getDefinitions();
-    foreach ($definitions as $plugin_id => &$definition) {
-      call_user_func_array($this->processCallback, array(&$definition, $plugin_id));
-    }
-    return $definitions;
-  }
-
-  /**
-   * Passes through all unknown calls onto the decorated object.
-   */
-  public function __call($method, $args) {
-    return call_user_func_array(array($this->decorated, $method), $args);
-  }
-
-}
diff --git a/core/lib/Drupal/Component/Plugin/Discovery/StaticDiscovery.php b/core/lib/Drupal/Component/Plugin/Discovery/StaticDiscovery.php
index de74fb5..1f0c724 100644
--- a/core/lib/Drupal/Component/Plugin/Discovery/StaticDiscovery.php
+++ b/core/lib/Drupal/Component/Plugin/Discovery/StaticDiscovery.php
@@ -11,14 +11,7 @@
  * A discovery mechanism that allows plugin definitions to be manually
  * registered rather than actively discovered.
  */
-class StaticDiscovery implements DiscoveryInterface {
-
-  /**
-   * The array of plugin definitions, keyed by plugin id.
-   *
-   * @var array
-   */
-  protected $definitions = array();
+class StaticDiscovery extends DiscoveryBase implements DiscoveryInterface {
 
   /**
    * Implements Drupal\Component\Plugin\Discovery\DiscoveryInterface::getDefinition().
@@ -28,13 +21,6 @@ public function getDefinition($base_plugin_id) {
   }
 
   /**
-   * Implements Drupal\Component\Plugin\Discovery\DiscoveryInterface::getDefinitions().
-   */
-  public function getDefinitions() {
-    return $this->definitions;
-  }
-
-  /**
    * Sets a plugin definition.
    */
   public function setDefinition($plugin, array $definition) {
diff --git a/core/lib/Drupal/Component/Plugin/PluginManagerBase.php b/core/lib/Drupal/Component/Plugin/PluginManagerBase.php
index fce7004..081aa1c 100644
--- a/core/lib/Drupal/Component/Plugin/PluginManagerBase.php
+++ b/core/lib/Drupal/Component/Plugin/PluginManagerBase.php
@@ -9,11 +9,12 @@
 
 use Drupal\Component\Utility\NestedArray;
 use Drupal\Component\Plugin\Discovery\CachedDiscoveryInterface;
+use Drupal\Component\Plugin\Discovery\DiscoveryBase;
 
 /**
  * Base class for plugin managers.
  */
-abstract class PluginManagerBase implements PluginManagerInterface, CachedDiscoveryInterface {
+abstract class PluginManagerBase extends DiscoveryBase implements PluginManagerInterface, CachedDiscoveryInterface {
 
   /**
    * The object that discovers plugins managed by this manager.
@@ -56,6 +57,7 @@ public function getDefinition($plugin_id) {
    * Implements Drupal\Component\Plugin\PluginManagerInterface::getDefinitions().
    */
   public function getDefinitions() {
+    $this->discovery->processDefaults();
     return $this->discovery->getDefinitions();
   }
 
diff --git a/core/lib/Drupal/Core/Entity/EntityManager.php b/core/lib/Drupal/Core/Entity/EntityManager.php
index 34feb10..e7fff60 100644
--- a/core/lib/Drupal/Core/Entity/EntityManager.php
+++ b/core/lib/Drupal/Core/Entity/EntityManager.php
@@ -9,7 +9,6 @@
 
 use Drupal\Component\Plugin\PluginManagerBase;
 use Drupal\Component\Plugin\Factory\DefaultFactory;
-use Drupal\Component\Plugin\Discovery\ProcessDecorator;
 use Drupal\Core\Plugin\Discovery\AlterDecorator;
 use Drupal\Core\Plugin\Discovery\AnnotatedClassDiscovery;
 use Drupal\Core\Plugin\Discovery\InfoHookDecorator;
@@ -231,9 +230,7 @@ public function __construct() {
     // Allow the plugin definition to be altered by hook_entity_info_alter().
     $this->discovery = new AnnotatedClassDiscovery('Core', 'Entity');
     $this->discovery = new InfoHookDecorator($this->discovery, 'entity_info');
-    $this->discovery = new AlterDecorator($this->discovery, 'entity_info');
-    // @todo Run process before altering, see http://drupal.org/node/1848964.
-    $this->discovery = new ProcessDecorator($this->discovery, array($this, 'processDefinition'));
+    $this->discovery = new AlterDecorator($this->discovery->useDefaults($this), 'entity_info');
     $this->factory = new DefaultFactory($this);
 
     // Entity type plugins includes translated strings, so each language is
diff --git a/core/lib/Drupal/Core/Plugin/Discovery/AlterDecorator.php b/core/lib/Drupal/Core/Plugin/Discovery/AlterDecorator.php
index 8bcee3f..a2d8bd9 100644
--- a/core/lib/Drupal/Core/Plugin/Discovery/AlterDecorator.php
+++ b/core/lib/Drupal/Core/Plugin/Discovery/AlterDecorator.php
@@ -8,11 +8,12 @@
 namespace Drupal\Core\Plugin\Discovery;
 
 use Drupal\Component\Plugin\Discovery\DiscoveryInterface;
+use Drupal\Component\Plugin\Discovery\DiscoveryBase;
 
 /**
  * Enables altering of discovered plugin definitions.
  */
-class AlterDecorator implements DiscoveryInterface {
+class AlterDecorator extends DiscoveryBase implements DiscoveryInterface {
   /**
    * The name of the alter hook that will be implemented by this discovery instance.
    *
@@ -42,28 +43,16 @@ public function __construct(DiscoveryInterface $decorated, $hook) {
     $this->hook = $hook;
   }
 
-  /**
-   * Implements Drupal\Component\Plugin\Discovery\DiscoveryInterface::getDefinition().
-   */
-  public function getDefinition($plugin_id) {
-    $definitions = $this->getDefinitions();
-    return isset($definitions[$plugin_id]) ? $definitions[$plugin_id] : NULL;
-  }
-
 
   /**
    * Implements Drupal\Component\Plugin\Discovery\DiscoveryInterface::getDefinitions().
    */
   public function getDefinitions() {
-    $definitions = $this->decorated->getDefinitions();
-    drupal_alter($this->hook, $definitions);
+    $definitions = parent::getDefinitions();
+    if (empty($definitions)) {
+      $definitions =  $this->decorated->getDefinitions();
+      drupal_alter($this->hook, $definitions);
+    }
     return $definitions;
   }
-
-  /**
-   * Passes through all unknown calls onto the decorated object.
-   */
-  public function __call($method, $args) {
-    return call_user_func_array(array($this->decorated, $method), $args);
-  }
 }
diff --git a/core/lib/Drupal/Core/Plugin/Discovery/AnnotatedClassDiscovery.php b/core/lib/Drupal/Core/Plugin/Discovery/AnnotatedClassDiscovery.php
index bd89a92..61565ed 100644
--- a/core/lib/Drupal/Core/Plugin/Discovery/AnnotatedClassDiscovery.php
+++ b/core/lib/Drupal/Core/Plugin/Discovery/AnnotatedClassDiscovery.php
@@ -9,6 +9,7 @@
 
 use DirectoryIterator;
 use Drupal\Component\Plugin\Discovery\DiscoveryInterface;
+use Drupal\Component\Plugin\Discovery\DiscoveryBase;
 use Drupal\Component\Reflection\MockFileFinder;
 use Drupal\Core\Annotation\Plugin;
 use Doctrine\Common\Annotations\AnnotationReader;
@@ -18,7 +19,7 @@
 /**
  * Defines a discovery mechanism to find annotated plugins in PSR-0 namespaces.
  */
-class AnnotatedClassDiscovery implements DiscoveryInterface {
+class AnnotatedClassDiscovery extends DiscoveryBase implements DiscoveryInterface {
 
   /**
    * Constructs an AnnotatedClassDiscovery object.
@@ -29,65 +30,59 @@ function __construct($owner, $type) {
   }
 
   /**
-   * Implements Drupal\Component\Plugin\Discovery\DiscoveryInterface::getDefinition().
-   */
-  public function getDefinition($plugin_id) {
-    $plugins = $this->getDefinitions();
-    return isset($plugins[$plugin_id]) ? $plugins[$plugin_id] : NULL;
-  }
-
-  /**
    * Implements Drupal\Component\Plugin\Discovery\DiscoveryInterface::getDefinitions().
    */
   public function getDefinitions() {
-    $definitions = array();
-    $reader = new AnnotationReader();
-    // Prevent @endlink from being parsed as an annotation.
-    $reader->addGlobalIgnoredName('endlink');
-
-    // Register the namespace of classes that can be used for annotations.
-    AnnotationRegistry::registerAutoloadNamespace('Drupal\Core\Annotation', array(DRUPAL_ROOT . '/core/lib'));
-    // Get all PSR-0 namespaces.
-    $namespaces = drupal_classloader()->getNamespaces();
-    foreach ($namespaces as $ns => $namespace_dirs) {
-
-      // OS-Safe directory separators.
-      $ns = str_replace('\\', DIRECTORY_SEPARATOR, $ns);
-
-      foreach ($namespace_dirs as $dir) {
-        // Check for the pre-determined directory structure to find plugins.
-        $prefix = implode(DIRECTORY_SEPARATOR, array(
-          $ns,
-          'Plugin',
-          $this->owner,
-          $this->type
-        ));
-        $dir .= DIRECTORY_SEPARATOR . $prefix;
-
-        // If the directory structure exists, look for classes.
-        if (file_exists($dir)) {
-          $directories = new DirectoryIterator($dir);
-          foreach ($directories as $fileinfo) {
-            // @todo Once core requires 5.3.6, use $fileinfo->getExtension().
-            if (pathinfo($fileinfo->getFilename(), PATHINFO_EXTENSION) == 'php') {
-              $class = str_replace(
-                DIRECTORY_SEPARATOR,
-                '\\',
-                $prefix . DIRECTORY_SEPARATOR . $fileinfo->getBasename('.php')
-              );
-
-              // The filename is already known, so there is no need to find the
-              // file. However, StaticReflectionParser needs a finder, so use a
-              // mock version.
-              $finder = MockFileFinder::create($fileinfo->getPathName());
-              $parser = new StaticReflectionParser($class, $finder);
-
-              if ($annotation = $reader->getClassAnnotation($parser->getReflectionClass(), 'Drupal\Core\Annotation\Plugin')) {
-                // AnnotationInterface::get() returns the array definition
-                // instead of requiring us to work with the annotation object.
-                $definition = $annotation->get();
-                $definition['class'] = $class;
-                $definitions[$definition['id']] = $definition;
+    $definitions = parent::getDefinitions();
+    if (empty($definitions)) {
+      $reader = new AnnotationReader();
+      // Prevent @endlink from being parsed as an annotation.
+      $reader->addGlobalIgnoredName('endlink');
+  
+      // Register the namespace of classes that can be used for annotations.
+      AnnotationRegistry::registerAutoloadNamespace('Drupal\Core\Annotation', array(DRUPAL_ROOT . '/core/lib'));
+      // Get all PSR-0 namespaces.
+      $namespaces = drupal_classloader()->getNamespaces();
+      foreach ($namespaces as $ns => $namespace_dirs) {
+  
+        // OS-Safe directory separators.
+        $ns = str_replace('\\', DIRECTORY_SEPARATOR, $ns);
+  
+        foreach ($namespace_dirs as $dir) {
+          // Check for the pre-determined directory structure to find plugins.
+          $prefix = implode(DIRECTORY_SEPARATOR, array(
+            $ns,
+            'Plugin',
+            $this->owner,
+            $this->type
+          ));
+          $dir .= DIRECTORY_SEPARATOR . $prefix;
+  
+          // If the directory structure exists, look for classes.
+          if (file_exists($dir)) {
+            $directories = new DirectoryIterator($dir);
+            foreach ($directories as $fileinfo) {
+              // @todo Once core requires 5.3.6, use $fileinfo->getExtension().
+              if (pathinfo($fileinfo->getFilename(), PATHINFO_EXTENSION) == 'php') {
+                $class = str_replace(
+                  DIRECTORY_SEPARATOR,
+                  '\\',
+                  $prefix . DIRECTORY_SEPARATOR . $fileinfo->getBasename('.php')
+                );
+  
+                // The filename is already known, so there is no need to find the
+                // file. However, StaticReflectionParser needs a finder, so use a
+                // mock version.
+                $finder = MockFileFinder::create($fileinfo->getPathName());
+                $parser = new StaticReflectionParser($class, $finder);
+  
+                if ($annotation = $reader->getClassAnnotation($parser->getReflectionClass(), 'Drupal\Core\Annotation\Plugin')) {
+                  // AnnotationInterface::get() returns the array definition
+                  // instead of requiring us to work with the annotation object.
+                  $definition = $annotation->get();
+                  $definition['class'] = $class;
+                  $definitions[$definition['id']] = $definition;
+                }
               }
             }
           }
diff --git a/core/lib/Drupal/Core/Plugin/Discovery/CacheDecorator.php b/core/lib/Drupal/Core/Plugin/Discovery/CacheDecorator.php
index 67d6cab..4858602 100644
--- a/core/lib/Drupal/Core/Plugin/Discovery/CacheDecorator.php
+++ b/core/lib/Drupal/Core/Plugin/Discovery/CacheDecorator.php
@@ -9,11 +9,12 @@
 
 use Drupal\Component\Plugin\Discovery\CachedDiscoveryInterface;
 use Drupal\Component\Plugin\Discovery\DiscoveryInterface;
+use Drupal\Component\Plugin\Discovery\DiscoveryBase;
 
 /**
  * Enables static and persistent caching of discovered plugin definitions.
  */
-class CacheDecorator implements CachedDiscoveryInterface {
+class CacheDecorator extends DiscoveryBase implements CachedDiscoveryInterface {
 
   /**
    * The cache key used to store the definition list.
@@ -62,21 +63,16 @@ public function __construct(DiscoveryInterface $decorated, $cache_key, $cache_bi
   }
 
   /**
-   * Implements Drupal\Component\Plugin\Discovery\DicoveryInterface::getDefinition().
-   */
-  public function getDefinition($plugin_id) {
-    $definitions = $this->getDefinitions();
-    return isset($definitions[$plugin_id]) ? $definitions[$plugin_id] : NULL;
-  }
-
-  /**
    * Implements Drupal\Component\Plugin\Discovery\DicoveryInterface::getDefinitions().
    */
   public function getDefinitions() {
-    $definitions = $this->getCachedDefinitions();
-    if (!isset($definitions)) {
-      $definitions = $this->decorated->getDefinitions();
-      $this->setCachedDefinitions($definitions);
+    $definitions = parent::getDefinitions();
+    if (empty($definitions)) {
+      $definitions = $this->getCachedDefinitions();
+      if (!isset($definitions)) {
+        $definitions = $this->decorated->getDefinitions();
+        $this->setCachedDefinitions($definitions);
+      }
     }
     return $definitions;
   }
@@ -119,11 +115,4 @@ public function clearCachedDefinitions() {
     }
     $this->definitions = NULL;
   }
-
-  /**
-   * Passes through all unknown calls onto the decorated object.
-   */
-  public function __call($method, $args) {
-    return call_user_func_array(array($this->decorated, $method), $args);
-  }
 }
diff --git a/core/lib/Drupal/Core/Plugin/Discovery/HookDiscovery.php b/core/lib/Drupal/Core/Plugin/Discovery/HookDiscovery.php
index 0c77a2f..f9ac8cf 100644
--- a/core/lib/Drupal/Core/Plugin/Discovery/HookDiscovery.php
+++ b/core/lib/Drupal/Core/Plugin/Discovery/HookDiscovery.php
@@ -8,11 +8,12 @@
 namespace Drupal\Core\Plugin\Discovery;
 
 use Drupal\Component\Plugin\Discovery\DiscoveryInterface;
+use Drupal\Component\Plugin\Discovery\DiscoveryBase;
 
 /**
  * Provides a hook-based plugin discovery class.
  */
-class HookDiscovery implements DiscoveryInterface {
+class HookDiscovery extends DiscoveryBase implements DiscoveryInterface {
 
   /**
    * The name of the hook that will be implemented by this discovery instance.
@@ -33,23 +34,17 @@ function __construct($hook) {
   }
 
   /**
-   * Implements Drupal\Component\Plugin\Discovery\DicoveryInterface::getDefinition().
-   */
-  public function getDefinition($plugin_id) {
-    $plugins = $this->getDefinitions();
-    return isset($plugins[$plugin_id]) ? $plugins[$plugin_id] : NULL;
-  }
-
-  /**
    * Implements Drupal\Component\Plugin\Discovery\DicoveryInterface::getDefinitions().
    */
   public function getDefinitions() {
-    $definitions = array();
-    foreach (module_implements($this->hook) as $module) {
-      $function = $module . '_' . $this->hook;
-      foreach ($function() as $plugin_id => $definition) {
-        $definition['module'] = $module;
-        $definitions[$plugin_id] = $definition;
+    $definitions = parent::getDefinitions();
+    if (empty($definitions)) {
+      foreach (module_implements($this->hook) as $module) {
+        $function = $module . '_' . $this->hook;
+        foreach ($function() as $plugin_id => $definition) {
+          $definition['module'] = $module;
+          $definitions[$plugin_id] = $definition;
+        }
       }
     }
     return $definitions;
diff --git a/core/lib/Drupal/Core/Plugin/Discovery/InfoHookDecorator.php b/core/lib/Drupal/Core/Plugin/Discovery/InfoHookDecorator.php
index 7ba8913..4db4853 100644
--- a/core/lib/Drupal/Core/Plugin/Discovery/InfoHookDecorator.php
+++ b/core/lib/Drupal/Core/Plugin/Discovery/InfoHookDecorator.php
@@ -8,11 +8,12 @@
 namespace Drupal\Core\Plugin\Discovery;
 
 use Drupal\Component\Plugin\Discovery\DiscoveryInterface;
+use Drupal\Component\Plugin\Discovery\DiscoveryBase;
 
 /**
  * Allows info hook implementations to enhance discovered plugin definitions.
  */
-class InfoHookDecorator implements DiscoveryInterface {
+class InfoHookDecorator extends DiscoveryBase implements DiscoveryInterface {
 
   /**
    * The Discovery object being decorated.
@@ -42,30 +43,17 @@ public function __construct(DiscoveryInterface $decorated, $hook) {
   }
 
   /**
-   * Implements Drupal\Component\Plugin\Discovery\DiscoveryInterface::getDefinition().
-   */
-  public function getDefinition($plugin_id) {
-    $definitions = $this->getDefinitions();
-    return isset($definitions[$plugin_id]) ? $definitions[$plugin_id] : NULL;
-  }
-
-  /**
    * Implements Drupal\Component\Plugin\Discovery\DiscoveryInterface::getDefinitions().
    */
   public function getDefinitions() {
-    $definitions = $this->decorated->getDefinitions();
-    foreach (module_implements($this->hook) as $module) {
-      $function = $module . '_' . $this->hook;
-      $function($definitions);
+    $definitions = parent::getDefinitions();
+    if (empty($definitions)) {
+      $definitions = $this->decorated->getDefinitions();
+      foreach (module_implements($this->hook) as $module) {
+        $function = $module . '_' . $this->hook;
+        $function($definitions);
+      }
     }
     return $definitions;
   }
-
-  /**
-   * Passes through all unknown calls onto the decorated object.
-   */
-  public function __call($method, $args) {
-    return call_user_func_array(array($this->decorated, $method), $args);
-  }
-
 }
diff --git a/core/modules/field/lib/Drupal/field/Plugin/Type/Formatter/FormatterPluginManager.php b/core/modules/field/lib/Drupal/field/Plugin/Type/Formatter/FormatterPluginManager.php
index 55d0e3f..911d440 100644
--- a/core/modules/field/lib/Drupal/field/Plugin/Type/Formatter/FormatterPluginManager.php
+++ b/core/modules/field/lib/Drupal/field/Plugin/Type/Formatter/FormatterPluginManager.php
@@ -8,7 +8,6 @@
 namespace Drupal\field\Plugin\Type\Formatter;
 
 use Drupal\Component\Plugin\PluginManagerBase;
-use Drupal\Component\Plugin\Discovery\ProcessDecorator;
 use Drupal\Core\Plugin\Discovery\CacheDecorator;
 use Drupal\Core\Plugin\Discovery\AnnotatedClassDiscovery;
 use Drupal\field\Plugin\Type\Formatter\FormatterLegacyDiscoveryDecorator;
@@ -33,8 +32,7 @@ class FormatterPluginManager extends PluginManagerBase {
   public function __construct() {
     $this->discovery = new AnnotatedClassDiscovery('field', 'formatter');
     $this->discovery = new FormatterLegacyDiscoveryDecorator($this->discovery);
-    $this->discovery = new ProcessDecorator($this->discovery, array($this, 'processDefinition'));
-    $this->discovery = new AlterDecorator($this->discovery, 'field_formatter_info');
+    $this->discovery = new AlterDecorator($this->discovery->useDefaults($this), 'field_formatter_info');
     $this->discovery = new CacheDecorator($this->discovery, 'field_formatter_types', 'field');
 
     $this->factory = new FormatterFactory($this);
diff --git a/core/modules/field/lib/Drupal/field/Plugin/Type/LegacyDiscoveryDecorator.php b/core/modules/field/lib/Drupal/field/Plugin/Type/LegacyDiscoveryDecorator.php
index 43aad82..034e63f 100644
--- a/core/modules/field/lib/Drupal/field/Plugin/Type/LegacyDiscoveryDecorator.php
+++ b/core/modules/field/lib/Drupal/field/Plugin/Type/LegacyDiscoveryDecorator.php
@@ -8,6 +8,7 @@
 namespace Drupal\field\Plugin\Type;
 
 use Drupal\Component\Plugin\Discovery\DiscoveryInterface;
+use Drupal\Component\Plugin\Discovery\DiscoveryBase;
 use Drupal\Core\Plugin\Discovery\HookDiscovery;
 
 /**
@@ -16,7 +17,7 @@
  * Legacy plugins are discovered through
  * Drupal\Core\Plugin\Discovery\HookDiscovery, and handled by a legacy class.
  */
-abstract class LegacyDiscoveryDecorator implements DiscoveryInterface {
+abstract class LegacyDiscoveryDecorator extends DiscoveryBase implements DiscoveryInterface {
 
   /**
    * The name of the hook for Drupal\Core\Plugin\Discovery\HookDiscovery.
@@ -44,30 +45,25 @@ public function __construct(DiscoveryInterface $decorated) {
   }
 
   /**
-   * Implements Drupal\Component\Plugin\Discovery\DiscoveryInterface::getDefinition().
-   */
-  public function getDefinition($plugin_id) {
-    $definitions = $this->getDefinitions();
-    return isset($definitions[$plugin_id]) ? $definitions[$plugin_id] : NULL;
-  }
-
-  /**
    * Implements Drupal\Component\Plugin\Discovery\DiscoveryInterface::getDefinitions().
    */
   public function getDefinitions() {
-    $definitions = $this->decorated->getDefinitions();
+    $definitions = parent::getDefinitions();
+    if (empty($definitions)) {
+      $definitions = $this->decorated->getDefinitions();
 
-    $legacy_discovery = new HookDiscovery($this->hook);
-    if ($legacy_definitions = $legacy_discovery->getDefinitions()) {
-      foreach ($legacy_definitions as $plugin_id => $definition) {
-        $this->processDefinition($definition);
+      $legacy_discovery = new HookDiscovery($this->hook);
+      if ($legacy_definitions = $legacy_discovery->getDefinitions()) {
+        foreach ($legacy_definitions as $plugin_id => $definition) {
+          $this->processDefinition($definition);
 
-        if (isset($definition['behaviors']['default value'])) {
-          $definition['default_value'] = $definition['behaviors']['default value'];
-          unset($definition['behaviors']['default value']);
-        }
+          if (isset($definition['behaviors']['default value'])) {
+            $definition['default_value'] = $definition['behaviors']['default value'];
+            unset($definition['behaviors']['default value']);
+          }
 
-        $definitions[$plugin_id] = $definition;
+          $definitions[$plugin_id] = $definition;
+        }
       }
     }
     return $definitions;
diff --git a/core/modules/field/lib/Drupal/field/Plugin/Type/Widget/WidgetPluginManager.php b/core/modules/field/lib/Drupal/field/Plugin/Type/Widget/WidgetPluginManager.php
index 5722807..490bef2 100644
--- a/core/modules/field/lib/Drupal/field/Plugin/Type/Widget/WidgetPluginManager.php
+++ b/core/modules/field/lib/Drupal/field/Plugin/Type/Widget/WidgetPluginManager.php
@@ -8,7 +8,6 @@
 namespace Drupal\field\Plugin\Type\Widget;
 
 use Drupal\Component\Plugin\PluginManagerBase;
-use Drupal\Component\Plugin\Discovery\ProcessDecorator;
 use Drupal\Core\Plugin\Discovery\CacheDecorator;
 use Drupal\Core\Plugin\Discovery\AlterDecorator;
 use Drupal\Core\Plugin\Discovery\AnnotatedClassDiscovery;
@@ -35,8 +34,7 @@ class WidgetPluginManager extends PluginManagerBase {
   public function __construct() {
     $this->discovery = new AnnotatedClassDiscovery('field', 'widget');
     $this->discovery = new WidgetLegacyDiscoveryDecorator($this->discovery);
-    $this->discovery = new ProcessDecorator($this->discovery, array($this, 'processDefinition'));
-    $this->discovery = new AlterDecorator($this->discovery, 'field_widget_info');
+    $this->discovery = new AlterDecorator($this->discovery->useDefaults($this), 'field_widget_info');
     $this->discovery = new CacheDecorator($this->discovery, 'field_widget_types',  'field');
 
     $this->factory = new WidgetFactory($this);
diff --git a/core/modules/layout/lib/Drupal/layout/Plugin/Type/LayoutManager.php b/core/modules/layout/lib/Drupal/layout/Plugin/Type/LayoutManager.php
index 8446fa8..2fbbee0 100644
--- a/core/modules/layout/lib/Drupal/layout/Plugin/Type/LayoutManager.php
+++ b/core/modules/layout/lib/Drupal/layout/Plugin/Type/LayoutManager.php
@@ -9,7 +9,6 @@
 
 use Drupal\Component\Plugin\PluginManagerBase;
 use Drupal\Component\Plugin\Discovery\DerivativeDiscoveryDecorator;
-use Drupal\Component\Plugin\Discovery\ProcessDecorator;
 use Drupal\Core\Plugin\Discovery\AnnotatedClassDiscovery;
 use Drupal\Component\Plugin\Factory\ReflectionFactory;
 
@@ -28,8 +27,7 @@ class LayoutManager extends PluginManagerBase {
   public function __construct() {
     // Create layout plugin derivatives from declaratively defined layouts.
     $this->discovery = new AnnotatedClassDiscovery('layout', 'layout');
-    $this->discovery = new DerivativeDiscoveryDecorator($this->discovery);
-    $this->discovery = new ProcessDecorator($this->discovery, array($this, 'processDefinition'));
+    $this->discovery = new DerivativeDiscoveryDecorator($this->discovery->useDefaults($this));
 
     $this->factory = new ReflectionFactory($this);
   }
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 a449c81..00ac39d 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
@@ -9,7 +9,6 @@
 
 use Drupal\Component\Plugin\PluginManagerBase;
 use Drupal\Component\Plugin\Discovery\StaticDiscovery;
-use Drupal\Component\Plugin\Discovery\ProcessDecorator;
 use Drupal\Component\Plugin\Factory\DefaultFactory;
 
 /**
@@ -23,7 +22,7 @@ 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->discovery = $this->discovery->useDefaults($this);
     $this->factory = new DefaultFactory($this);
 
     // Specify default values.
diff --git a/core/modules/views/lib/Drupal/views/Plugin/Type/JoinManager.php b/core/modules/views/lib/Drupal/views/Plugin/Type/JoinManager.php
index 2ed3f99..b627fc5 100644
--- a/core/modules/views/lib/Drupal/views/Plugin/Type/JoinManager.php
+++ b/core/modules/views/lib/Drupal/views/Plugin/Type/JoinManager.php
@@ -9,7 +9,6 @@
 
 use Drupal\Component\Plugin\PluginManagerBase;
 use Drupal\Component\Plugin\Factory\DefaultFactory;
-use Drupal\Component\Plugin\Discovery\ProcessDecorator;
 use Drupal\Core\Plugin\Discovery\AlterDecorator;
 use Drupal\Core\Plugin\Discovery\AnnotatedClassDiscovery;
 use Drupal\Core\Plugin\Discovery\CacheDecorator;
@@ -22,8 +21,7 @@ class JoinManager extends PluginManagerBase {
   public function __construct() {
     $this->discovery = new AnnotatedClassDiscovery('views', 'join');
     $this->discovery = new AlterDecorator($this->discovery, 'views_plugins_join');
-    $this->discovery = new ProcessDecorator($this->discovery, array($this, 'processDefinition'));
-    $this->discovery = new CacheDecorator($this->discovery, 'views:join', 'views_info');
+    $this->discovery = new CacheDecorator($this->discovery->useDefaults($this), 'views:join', 'views_info');
 
     $this->factory = new DefaultFactory($this);
     $this->defaults = array(
diff --git a/core/modules/views/lib/Drupal/views/Plugin/Type/PluginManager.php b/core/modules/views/lib/Drupal/views/Plugin/Type/PluginManager.php
index 354c106..1a05018 100644
--- a/core/modules/views/lib/Drupal/views/Plugin/Type/PluginManager.php
+++ b/core/modules/views/lib/Drupal/views/Plugin/Type/PluginManager.php
@@ -9,7 +9,6 @@
 
 use Drupal\Component\Plugin\PluginManagerBase;
 use Drupal\Component\Plugin\Factory\DefaultFactory;
-use Drupal\Component\Plugin\Discovery\ProcessDecorator;
 use Drupal\Core\Plugin\Discovery\AlterDecorator;
 use Drupal\Core\Plugin\Discovery\AnnotatedClassDiscovery;
 use Drupal\Core\Plugin\Discovery\CacheDecorator;
@@ -22,8 +21,7 @@ class PluginManager extends PluginManagerBase {
   public function __construct($type) {
     $this->discovery = new AnnotatedClassDiscovery('views', $type);
     $this->discovery = new AlterDecorator($this->discovery, 'views_plugins_' . $type);
-    $this->discovery = new ProcessDecorator($this->discovery, array($this, 'processDefinition'));
-    $this->discovery = new CacheDecorator($this->discovery, 'views:' . $type, 'views_info');
+    $this->discovery = new CacheDecorator($this->discovery->useDefaults($this), 'views:' . $type, 'views_info');
 
     $this->factory = new DefaultFactory($this);
     $this->defaults += array(
diff --git a/core/modules/views/lib/Drupal/views/Plugin/Type/WizardManager.php b/core/modules/views/lib/Drupal/views/Plugin/Type/WizardManager.php
index 8a0aed5..1c8aa34 100644
--- a/core/modules/views/lib/Drupal/views/Plugin/Type/WizardManager.php
+++ b/core/modules/views/lib/Drupal/views/Plugin/Type/WizardManager.php
@@ -9,7 +9,6 @@
 
 use Drupal\Component\Plugin\PluginManagerBase;
 use Drupal\Component\Plugin\Factory\DefaultFactory;
-use Drupal\Component\Plugin\Discovery\ProcessDecorator;
 use Drupal\Core\Plugin\Discovery\AlterDecorator;
 use Drupal\Core\Plugin\Discovery\AnnotatedClassDiscovery;
 use Drupal\Core\Plugin\Discovery\CacheDecorator;
@@ -22,8 +21,7 @@ class WizardManager extends PluginManagerBase {
   public function __construct() {
     $this->discovery = new AnnotatedClassDiscovery('views', 'wizard');
     $this->discovery = new AlterDecorator($this->discovery, 'views_plugins_wizard');
-    $this->discovery = new ProcessDecorator($this->discovery, array($this, 'processDefinition'));
-    $this->discovery = new CacheDecorator($this->discovery, 'views:wizard', 'views_info');
+    $this->discovery = new CacheDecorator($this->discovery->useDefaults($this), 'views:wizard', 'views_info');
     $this->factory = new DefaultFactory($this);
     $this->defaults = array(
       'module' => 'views',
