diff --git a/core/lib/Drupal/Component/Plugin/Derivative/DerivativeInterface.php b/core/lib/Drupal/Component/Plugin/Derivative/DerivativeInterface.php
index 281a4ca..43f20a1 100644
--- a/core/lib/Drupal/Component/Plugin/Derivative/DerivativeInterface.php
+++ b/core/lib/Drupal/Component/Plugin/Derivative/DerivativeInterface.php
@@ -1,36 +1,49 @@
 <?php
 /**
  * @file
- * Interface implemented by plugins needing children support.
+ * Interface implemented by plugins needing derivative support.
  */
 
 namespace Drupal\Component\Plugin\Derivative;
 
 /**
- * Plugin interface for child plugin handling.
+ * Plugin interface for derivative plugin handling.
  */
 interface DerivativeInterface {
 
-
-  public function __construct($scope, $type, $plugin, array $config);
-
   /**
-   * Set a specific derivative for the instance to return.
+   * Returns the definition of a derivative plugin.
+   *
+   * @param $derivativeId
+   *   The derivative id. The id must uniquely identify the derivative within a
+   *   given base plugin, but derivative ids can be reused across base plugins.
+   *   Implementations of
+   *   Drupal\Component\Plugin\Discovery\DerivativeDiscoveryInterface combine
+   *   the base plugin id with $derivativeId to construct the derivative's full
+   *   plugin id.
+   *
+   * @param $basePluginDefinition
+   *   The definition array of the base plugin from which the derivative plugin
+   *   is derived.
    *
-   * @param array $config
-   *   The generic plugin
    * @return
-   *   A Configuration array specific to the requested derivative.
+   *   The full definition array of the derivative plugin, typically a merge of
+   *   $basePluginDefinition with extra derivative-specific information. NULL if
+   *   the derivative doesn't exist.
    */
-  public function getDerivative($key);
+  public function getDerivativeDefinition($derivativeId, array $basePluginDefinition);
 
   /**
-   * Get the configurations for all possible derivatives.
+   * Returns the definition of all derivatives of a base plugin.
+   *
+   * @param $basePluginDefinition
+   *   The definition array of the base plugin.
    *
    * @return
-   *   An array of Configuration objects for all potential derivatives of this
-   *   plugin implementation.
+   *   An array of full derivative definitions keyed on derivative id.
+   *
+   * @see getDerivativeDefinition()
    */
-  public function getDerivatives();
+  public function getDerivativeDefinitions(array $basePluginDefinition);
 
 }
diff --git a/core/lib/Drupal/Component/Plugin/Derivative/StaticDerivativeInterface.php b/core/lib/Drupal/Component/Plugin/Derivative/StaticDerivativeInterface.php
new file mode 100644
index 0000000..172afb6
--- /dev/null
+++ b/core/lib/Drupal/Component/Plugin/Derivative/StaticDerivativeInterface.php
@@ -0,0 +1,66 @@
+<?php
+/**
+ * @file
+ * Interface implemented by plugins needing derivative support.
+ */
+
+namespace Drupal\Component\Plugin\Derivative;
+use Drupal\Component\Plugin\PluginTypeInterface;
+
+/**
+ * Plugin interface for derivative plugin handling.
+ *
+ * All methods within this interface are static, so that this interface can be
+ * implemented by the plugin class itself, without requiring creating a plugin
+ * instance in order to get derivative definitions.
+ */
+interface StaticDerivativeInterface {
+
+  /**
+   * Returns the definition of a derivative plugin.
+   *
+   * @param $derivativeId
+   *   The derivative id. The id must uniquely identify the derivative within a
+   *   given base plugin, but derivative ids can be reused across base plugins.
+   *   Implementations of
+   *   Drupal\Component\Plugin\Discovery\DerivativeDiscoveryInterface combine
+   *   $basePluginId with $derivativeId to construct the derivative's full
+   *   plugin id.
+   *
+   * @param $basePluginDefinition
+   *   The definition array of the base plugin from which the derivative plugin
+   *   is derived.
+   *
+   * @param $basePluginId
+   *   The base plugin identifier.
+   *
+   * @param $pluginType
+   *   The plugin type object.
+   *
+   * @return
+   *   The full definition array of the derivative plugin, typically a merge of
+   *   $basePluginDefinition with extra derivative-specific information. NULL if
+   *   the derivative doesn't exist.
+   */
+  public static function getDerivativeDefinition($derivativeId, array $basePluginDefinition, $basePluginId, PluginTypeInterface $pluginType);
+
+  /**
+   * Returns the definition of all derivatives of a base plugin.
+   *
+   * @param $basePluginDefinition
+   *   The definition array of the base plugin.
+   *
+   * @param $basePluginId
+   *   The base plugin identifier.
+   *
+   * @param $pluginType
+   *   The plugin type object.
+   *
+   * @return
+   *   An array of full derivative definitions keyed on derivative id.
+   *
+   * @see getDerivativeDefinition()
+   */
+  public static function getDerivativeDefinitions(array $basePluginDefinition, $basePluginId, PluginTypeInterface $pluginType);
+
+}
diff --git a/core/lib/Drupal/Component/Plugin/Discovery/DerivativeDiscovery.php b/core/lib/Drupal/Component/Plugin/Discovery/DerivativeDiscovery.php
new file mode 100644
index 0000000..f5237e4
--- /dev/null
+++ b/core/lib/Drupal/Component/Plugin/Discovery/DerivativeDiscovery.php
@@ -0,0 +1,88 @@
+<?php
+
+/**
+ * @file
+ * ...
+ */
+
+namespace Drupal\Component\Plugin\Discovery;
+
+class DerivativeDiscovery implements DerivativeDiscoveryInterface {
+
+  protected $pluginType;
+  protected $classKey;
+  protected $implementors = array();
+
+  public function __construct($pluginType, $classKey) {
+    $this->pluginType = $pluginType;
+    $this->classKey = $classKey;
+  }
+
+  public function getBasePluginId($pluginId) {
+    return (($pos = strpos($pluginId, ':')) ? substr($pluginId, 0, $pos) : $pluginId);
+  }
+
+  public function getPluginDefinition($pluginId, array $baseDefinition) {
+    $basePluginId = $this->getBasePluginId($pluginId);
+    $implementor = $this->getDerivativeClassOrObject($basePluginId, $baseDefinition);
+    if ($pluginId == $basePluginId) {
+      if (isset($implementor)) {
+        // Some plugins allow independent existence of the base plugin
+        // (derivativeId = NULL), some do not (by returning a NULL definition).
+        $definition = is_object($implementor) ? $implementor->getDerivativeDefinition(NULL, $baseDefinition) : $implementor::getDerivativeDefinition(NULL, $baseDefinition, $basePluginId, $this->pluginType);
+      }
+      else {
+        $definition = $baseDefinition;
+      }
+    }
+    elseif (isset($implementor)) {
+      $derivativeId = substr($pluginId, strlen($basePluginId)+1);
+      $definition = is_object($implementor) ? $implementor->getDerivativeDefinition($derivativeId, $baseDefinition) : $implementor::getDerivativeDefinition($derivativeId, $baseDefinition, $basePluginId, $this->pluginType);
+    }
+    else {
+      $definition = NULL;
+    }
+    return $definition;
+  }
+
+  public function getPluginDefinitions($basePluginId, array $baseDefinition) {
+    $definitions = array();
+    $implementor = $this->getDerivativeClassOrObject($basePluginId, $baseDefinition);
+    if (isset($implementor)) {
+      $derivativeDefinitions = is_object($implementor) ? $implementor->getDerivativeDefinitions($baseDefinition) : $implementor::getDerivativeDefinitions($baseDefinition, $basePluginId, $this->pluginType);
+      foreach ($derivativeDefinitions as $derivativeId => $definition) {
+        $pluginId = strlen($derivativeId) ? "$basePluginId:$derivativeId" : $basePluginId;
+        $definitions[$pluginId] = $definition;
+      }
+    }
+    else {
+      $definitions[$basePluginId] = $baseDefinition;
+    }
+    return $definitions;
+  }
+
+  /**
+   * Returns the object that implements DerivativeInterface or class that implements StaticDerivativeInterface on behalf of the plugin.
+   *
+   * Returns NULL if the plugin doesn't define a value for this class, or if the
+   * class doesn't implement the required interface. Not throwing an error for
+   * either of these cases allows for flexibility in allowing but not requiring
+   * plugin classes to directly handle their own derivative fetching.
+   */
+  protected function getDerivativeClassOrObject($basePluginId, $baseDefinition) {
+    if (!isset($this->implementors[$basePluginId])) {
+      $this->implementors[$basePluginId] = FALSE;
+      if (isset($baseDefinition[$this->classKey])) {
+        $class = $baseDefinition[$this->classKey];
+        $reflector = new \ReflectionClass($class);
+        if ($reflector->implementsInterface('Drupal\Component\Plugin\Derivative\DerivativeInterface')) {
+          $this->implementors[$basePluginId] = new $class($basePluginId, $this->pluginType);
+        }
+        elseif ($reflector->implementsInterface('Drupal\Component\Plugin\Derivative\StaticDerivativeInterface')) {
+          $this->implementors[$basePluginId] = $class;
+        }
+      }
+    }
+    return $this->implementors[$basePluginId] ? $this->implementors[$basePluginId] : NULL;
+  }
+}
diff --git a/core/lib/Drupal/Component/Plugin/Discovery/DerivativeDiscoveryInterface.php b/core/lib/Drupal/Component/Plugin/Discovery/DerivativeDiscoveryInterface.php
new file mode 100644
index 0000000..c67c9a3
--- /dev/null
+++ b/core/lib/Drupal/Component/Plugin/Discovery/DerivativeDiscoveryInterface.php
@@ -0,0 +1,18 @@
+<?php
+
+/**
+ * @file
+ * ...
+ */
+
+namespace Drupal\Component\Plugin\Discovery;
+
+interface DerivativeDiscoveryInterface {
+
+  public function getBasePluginId($pluginId);
+
+  public function getPluginDefinition($pluginId, array $baseDefinition);
+
+  public function getPluginDefinitions($basePluginId, array $baseDefinition);
+
+}
diff --git a/core/lib/Drupal/Component/Plugin/Discovery/NullDerivativeDiscovery.php b/core/lib/Drupal/Component/Plugin/Discovery/NullDerivativeDiscovery.php
new file mode 100644
index 0000000..ca02f1d
--- /dev/null
+++ b/core/lib/Drupal/Component/Plugin/Discovery/NullDerivativeDiscovery.php
@@ -0,0 +1,24 @@
+<?php
+
+/**
+ * @file
+ * ...
+ */
+
+namespace Drupal\Component\Plugin\Discovery;
+
+class NullDerivativeDiscovery implements DerivativeDiscoveryInterface {
+
+  public function getBasePluginId($pluginId) {
+    return $pluginId;
+  }
+
+  public function getPluginDefinition($pluginId, array $baseDefinition) {
+    return $baseDefinition;
+  }
+
+  public function getPluginDefinition($basePluginId, array $baseDefinition) {
+    return array($basePluginId => $baseDefinition);
+  }
+
+}
diff --git a/core/lib/Drupal/Component/Plugin/Discovery/StaticDiscovery.php b/core/lib/Drupal/Component/Plugin/Discovery/StaticDiscovery.php
index 97bd093..981aa82 100644
--- a/core/lib/Drupal/Component/Plugin/Discovery/StaticDiscovery.php
+++ b/core/lib/Drupal/Component/Plugin/Discovery/StaticDiscovery.php
@@ -19,24 +19,37 @@ class StaticDiscovery implements DiscoveryInterface {
    */
   protected $pluginType;
 
+  /**
+   * The derivative discovery object.
+   *
+   * @var DerivativeDiscoveryInterface
+   */
+  protected $derivativeDiscovery;
+
   protected $plugin_definitions = array();
 
-  public function __construct(PluginTypeInterface $plugin_type) {
+  public function __construct(PluginTypeInterface $plugin_type, DerivativeDiscoveryInterface $derivativeDiscovery = NULL) {
     $this->pluginType = $plugin_type;
+    $this->derivativeDiscovery = isset($derivativeDiscovery) ? $derivativeDiscovery : new NullDerivativeDiscovery();
   }
 
   /**
    * Implements DiscoveryInterface::getPluginDefinition().
    */
   public function getPluginDefinition($plugin_id) {
-    return isset($this->plugin_definitions[$plugin_id]) ? $this->plugin_definitions[$plugin_id] : array();
+    $baseDefinition = $this->plugin_definitions[$this->derivativeDiscovery->getBasePluginId($plugin_id)];
+    return $this->derivativeDiscovery->getPluginDefinition($plugin_id, $baseDefinition);
   }
 
   /**
    * Implements DiscoveryInterface::getPluginDefinitions().
    */
   public function getPluginDefinitions() {
-    return isset($this->plugin_definitions) ? $this->plugin_definitions : array();
+    $definitions = array();
+    foreach ($this->plugin_definitions as $basePluginid => $baseDefinition) {
+      $definitions += $this->derivativeDiscovery->getPluginDefinitions($basePluginid, $baseDefinition);
+    }
+    return $definitions;
   }
 
   /**
diff --git a/core/lib/Drupal/Component/Plugin/Factory/DefaultFactory.php b/core/lib/Drupal/Component/Plugin/Factory/DefaultFactory.php
index 2a40db1..e276c03 100644
--- a/core/lib/Drupal/Component/Plugin/Factory/DefaultFactory.php
+++ b/core/lib/Drupal/Component/Plugin/Factory/DefaultFactory.php
@@ -44,7 +44,7 @@ class DefaultFactory implements FactoryInterface {
       $params = $reflector->getMethod('__construct')->getParameters();
       $arguments = array();
       foreach ($params as $param) {
-        $arguments[$param->name] = $configuration[$param->name];
+        $arguments[$param->name] = isset($configuration[$param->name]) ? $configuration[$param->name] : NULL;
       }
       $instance = $reflector->newInstanceArgs($arguments);
     }
diff --git a/core/lib/Drupal/Component/Plugin/Mapper/MapperInterface.php b/core/lib/Drupal/Component/Plugin/Mapper/MapperInterface.php
index 221ba40..d17118a 100644
--- a/core/lib/Drupal/Component/Plugin/Mapper/MapperInterface.php
+++ b/core/lib/Drupal/Component/Plugin/Mapper/MapperInterface.php
@@ -20,16 +20,6 @@ use Drupal\Component\Plugin\Factory\FactoryInterface;
 interface MapperInterface {
 
   /**
-   * Construct a plugin factory.
-   *
-   * @param DiscoveryInterface $discovery
-   *   A discovery object for finding out implementation information.
-   * @param FactoryInterface $discovery
-   *   A discovery object for finding out implementation information.
-   */
-  public function __construct(DiscoveryInterface $discovery, FactoryInterface $factory);
-
-  /**
    * Responsible for returning a preconfigured instance of a plugin.
    *
    * @param array $options
diff --git a/core/lib/Drupal/Component/Plugin/PluginType.php b/core/lib/Drupal/Component/Plugin/PluginType.php
index a8c8197..9917a84 100644
--- a/core/lib/Drupal/Component/Plugin/PluginType.php
+++ b/core/lib/Drupal/Component/Plugin/PluginType.php
@@ -36,6 +36,7 @@ abstract class PluginType implements PluginTypeInterface {
    */
   public function processPluginDefinition(&$definition) {
     $definition += $this->defaults;
+    return $definition;
   }
 
   /**
diff --git a/core/lib/Drupal/Core/Plugin/Discovery/ConfigDiscovery.php b/core/lib/Drupal/Core/Plugin/Discovery/ConfigDiscovery.php
index 2f690e8..07a1e9e 100644
--- a/core/lib/Drupal/Core/Plugin/Discovery/ConfigDiscovery.php
+++ b/core/lib/Drupal/Core/Plugin/Discovery/ConfigDiscovery.php
@@ -6,8 +6,9 @@
  */
 
 namespace Drupal\Core\Plugin\Discovery;
-use Drupal\Component\Plugin\Discovery\DiscoveryInterface;
 use Drupal\Component\Plugin\PluginTypeInterface;
+use Drupal\Component\Plugin\Discovery\DerivativeDiscoveryInterface;
+use Drupal\Component\Plugin\Discovery\NullDerivativeDiscovery;
 
 class ConfigDiscovery implements DiscoveryInterface {
 
@@ -18,41 +19,42 @@ class ConfigDiscovery implements DiscoveryInterface {
    */
   protected $pluginType;
 
+  /**
+   * The derivative discovery object.
+   *
+   * @var DerivativeDiscoveryInterface
+   */
+  protected $derivativeDiscovery;
+
   protected $definition_root;
 
-  function __construct(PluginTypeInterface $plugin_type, $definition_root = NULL) {
+  function __construct(PluginTypeInterface $plugin_type, $definition_root = NULL, DerivativeDiscoveryInterface $derivativeDiscovery = NULL) {
     $this->pluginType = $plugin_type;
     $this->definition_root = $definition_root;
+    $this->derivativeDiscovery = isset($derivativeDiscovery) ? $derivativeDiscovery : new NullDerivativeDiscovery();
   }
 
   /**
    * Implements DicoveryInterface::getPluginDefinition().
    */
   public function getPluginDefinition($plugin_id) {
-    $config = config("{$this->definition_root}.$plugin_id")->get();
-    if ($config['derivative']) {
-      $derviative_mapper = new $config['derivative']($this->definition_root, $plugin_id, $config);
-      $config = $derviative_mapper->getDerviative($plugin_id);
-    }
-    return $this->pluginType->processPluginDefinition($config);
+    $basePluginId = $this->derivativeDiscovery->getBasePluginId($plugin_id);
+    $baseDefinition = config("{$this->definition_root}.$basePluginId")->get();
+    $this->pluginType->processPluginDefinition($baseDefinition);
+    return $this->derivativeDiscovery->getPluginDefinition($plugin_id, $baseDefinition);
   }
 
   /**
    * Implements DicoveryInterface::getPluginDefinitions().
    */
   public function getPluginDefinitions() {
-    $plugins = array();
-    foreach (config_get_signed_file_storage_names_with_prefix($this->definition_root) as $plugin_id) {
-      $plugins[$plugin_id] = config($plugin_id)->get();
-      if (!empty($plugins[$plugin_id]['derivative'])) {
-        $derviative_mapper = new $plugins[$plugin_id]['derivative']($this->definition_root, $plugin_id, $plugins[$plugin_id]);
-        $derivatives = $derviative_mapper->getDerivatives();
-        foreach ($derivatives as $derivative_id => $derivative) {
-          $plugins[$derivative_id] = $this->pluginType->processPluginDefinition($derivative);
-        }
-        unset($plugins[$plugin_id]);
-      }
+    $definitions = array();
+    foreach (config_get_signed_file_storage_names_with_prefix($this->definition_root) as $config_name) {
+      $basePluginId = substr($config_name, strlen($this->definition_root) + 1);
+      $baseDefinition = config($config_name)->get();
+      $this->pluginType->processPluginDefinition($baseDefinition);
+      $definitions += $this->derivativeDiscovery->getPluginDefinitions($basePluginId, $baseDefinition);
     }
-    return $plugins;
+    return $definitions;
   }
 }
diff --git a/core/modules/system/tests/modules/plugin_test/lib/Drupal/plugin_test/Plugin/Derivative/DerivativeTest.php b/core/modules/system/tests/modules/plugin_test/lib/Drupal/plugin_test/Plugin/Derivative/DerivativeTest.php
new file mode 100644
index 0000000..dc899f8
--- /dev/null
+++ b/core/modules/system/tests/modules/plugin_test/lib/Drupal/plugin_test/Plugin/Derivative/DerivativeTest.php
@@ -0,0 +1,37 @@
+<?php
+
+namespace Drupal\plugin_test\Plugin\Derivative;
+
+use Drupal\Component\Plugin\Derivative\DerivativeInterface;
+use Drupal\Component\Plugin\PluginTypeInterface;
+
+class DerivativeTest implements DerivativeInterface {
+
+  /**
+   * Implements DerivativeInterface::getDerivativeDefinition().
+   */
+  public function getDerivativeDefinition($derivativeId, array $basePluginDefinition) {
+    $derivatives = $this->getDerivativeDefinitions($basePluginDefinition);
+    if (isset($derivatives[$derivativeId])) {
+      return $derivatives[$derivativeId];
+    }
+  }
+
+  /**
+   * Implements DerivativeInterface::getDerivativeDefinitions().
+   */
+  public function getDerivativeDefinitions(array $basePluginDefinition) {
+    $derivatives = array(
+      'test1' => array(
+        'string' => 'Test String 1',
+      ) + $basePluginDefinition,
+      'test2' => array(
+        'string' => 'Test String 2',
+      ) + $basePluginDefinition,
+    );
+    if (!empty($basePluginDefinition['use_base'])) {
+      $derivatives[NULL] = $basePluginDefinition;
+    }
+    return $derivatives;
+  }
+}
diff --git a/core/modules/system/tests/modules/plugin_test/lib/Drupal/plugin_test/Plugin/TestDerivablePlugin.php b/core/modules/system/tests/modules/plugin_test/lib/Drupal/plugin_test/Plugin/TestDerivablePlugin.php
new file mode 100644
index 0000000..4fa70b6
--- /dev/null
+++ b/core/modules/system/tests/modules/plugin_test/lib/Drupal/plugin_test/Plugin/TestDerivablePlugin.php
@@ -0,0 +1,47 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\plugin_test\Plugin\TestDerivablePlugin.
+ */
+
+namespace Drupal\plugin_test\Plugin;
+use Drupal\Component\Plugin\PluginAbstract;
+use Drupal\Component\Plugin\PluginTypeInterface;
+use Drupal\Component\Plugin\Derivative\StaticDerivativeInterface;
+
+class TestDerivablePlugin extends PluginAbstract implements StaticDerivativeInterface {
+  protected $string;
+
+  public function __construct($string) {
+    $this->string = $string;
+  }
+
+  public function string() {
+    return $this->string;
+  }
+
+  /**
+   * Implements StaticDerivativeInterface::getDerivativeDefinition().
+   */
+  public static function getDerivativeDefinition($derivativeId, array $basePluginDefinition, $basePluginId, PluginTypeInterface $pluginType) {
+    $derivatives = self::getDerivativeDefinitions($basePluginDefinition, $basePluginId, $pluginType);
+    if (isset($derivatives[$derivativeId])) {
+      return $derivatives[$derivativeId];
+    }
+  }
+
+  /**
+   * Implements StaticDerivativeInterface::getDerivativeDefinitions().
+   */
+  public static function getDerivativeDefinitions(array $basePluginDefinition, $basePluginId, PluginTypeInterface $pluginType) {
+    return array(
+      'test1' => array(
+        'string' => 'Test String 1',
+      ) + $basePluginDefinition,
+      'test2' => array(
+        'string' => 'Test String 2',
+      ) + $basePluginDefinition,
+    );
+  }
+}
diff --git a/core/modules/system/tests/modules/plugin_test/lib/Drupal/plugin_test/Plugin/TestPluginInstanceClass.php b/core/modules/system/tests/modules/plugin_test/lib/Drupal/plugin_test/Plugin/TestPluginInstanceClass.php
index 0febf83..ed33ad4 100644
--- a/core/modules/system/tests/modules/plugin_test/lib/Drupal/plugin_test/Plugin/TestPluginInstanceClass.php
+++ b/core/modules/system/tests/modules/plugin_test/lib/Drupal/plugin_test/Plugin/TestPluginInstanceClass.php
@@ -9,4 +9,13 @@ namespace Drupal\plugin_test\Plugin;
 use Drupal\Component\Plugin\PluginAbstract;
 
 class TestPluginInstanceClass extends PluginAbstract {
+  protected $string;
+
+  public function __construct($string) {
+    $this->string = $string;
+  }
+
+  public function string() {
+    return $this->string;
+  }
 }
diff --git a/core/modules/system/tests/modules/plugin_test/lib/Drupal/plugin_test/Plugin/Type/TestPluginType.php b/core/modules/system/tests/modules/plugin_test/lib/Drupal/plugin_test/Plugin/Type/TestPluginType.php
index d54e4d0..7e126c7 100644
--- a/core/modules/system/tests/modules/plugin_test/lib/Drupal/plugin_test/Plugin/Type/TestPluginType.php
+++ b/core/modules/system/tests/modules/plugin_test/lib/Drupal/plugin_test/Plugin/Type/TestPluginType.php
@@ -7,17 +7,34 @@
 
 namespace Drupal\plugin_test\Plugin\Type;
 use Drupal\Component\Plugin\PluginType;
+use Drupal\Component\Plugin\Discovery\DerivativeDiscovery;
 use Drupal\Component\Plugin\Discovery\StaticDiscovery;
 use Drupal\Component\Plugin\Mapper\DefaultMapper;
 use Drupal\Component\Plugin\Factory\DefaultFactory;
 
 class TestPluginType extends PluginType {
   public function __construct() {
-    $this->discovery = new StaticDiscovery($this);
+    $this->discovery = new StaticDiscovery($this, new DerivativeDiscovery($this, 'derivative'));
     $this->discovery->setPluginDefinition('coolaid', array(
       'string' => 'oh yeah',
       'class' => 'Drupal\plugin_test\Plugin\TestPluginInstanceClass',
     ));
+    $this->discovery->setPluginDefinition('beer', array(
+      'string' => 'derivative test',
+      'class' => 'Drupal\plugin_test\Plugin\TestPluginInstanceClass',
+      'derivative' => 'Drupal\plugin_test\Plugin\Derivative\DerivativeTest',
+      'use_base' => TRUE,
+    ));
+    $this->discovery->setPluginDefinition('wine', array(
+      'string' => 'derivative test',
+      'class' => 'Drupal\plugin_test\Plugin\TestPluginInstanceClass',
+      'derivative' => 'Drupal\plugin_test\Plugin\Derivative\DerivativeTest',
+    ));
+    $this->discovery->setPluginDefinition('scotch', array(
+      'string' => 'derivative test',
+      'class' => 'Drupal\plugin_test\Plugin\TestDerivablePlugin',
+      'derivative' => 'Drupal\plugin_test\Plugin\TestDerivablePlugin',
+    ));
     $this->factory = new DefaultFactory($this, 'class');
     $this->mapper = new DefaultMapper($this);
   }
diff --git a/core/modules/system/tests/plugins.test b/core/modules/system/tests/plugins.test
index 0966593..1342579 100644
--- a/core/modules/system/tests/plugins.test
+++ b/core/modules/system/tests/plugins.test
@@ -68,7 +68,79 @@ class PluginTestCase extends PluginUnitTestCase {
   }
 
   function testPluginInstanceFetching() {
-    $plugin = $this->TestPluginType->createPluginInstance('coolaid');
+    $plugin = $this->TestPluginType->createPluginInstance('coolaid', array('string' => 'this is a test'));
     $this->assertEqual(get_class($plugin), 'Drupal\plugin_test\Plugin\TestPluginInstanceClass', 'Correct plugin instance implementation returned by the test plugin type.');
+    $this->assertEqual($plugin->string(), 'this is a test', 'Plugin instance returns the proper string');
+  }
+
+  function testPluginDerivativeDefintionFetching() {
+    $plugin_definition = $this->TestPluginType->getPluginDefinition('beer:test1');
+    $this->assertEqual($plugin_definition['string'], 'Test String 1', 'Plugin derivative definition retrievable by the test plugin type.');
+  }
+
+  function testPluginEmptyDerivativeDefintionFetching() {
+    $plugin_definition = $this->TestPluginType->getPluginDefinition('beer');
+    $this->assertEqual($plugin_definition['string'], 'derivative test', 'Plugin derivative base returns the proper string');
+  }
+
+  function testPluginInstanceDerivativeFetching() {
+    $plugin_definition = $this->TestPluginType->getPluginDefinition('beer:test1');
+    $plugin = $this->TestPluginType->createPluginInstance('beer:test1', $plugin_definition);
+    $this->assertEqual($plugin->string(), 'Test String 1', 'Plugin derivative instance 1 returns the proper string');
+
+    $plugin_definition = $this->TestPluginType->getPluginDefinition('beer:test2');
+    $plugin = $this->TestPluginType->createPluginInstance('beer:test2', $plugin_definition);
+    $this->assertEqual($plugin->string(), 'Test String 2', 'Plugin derivative instance 2 returns the proper string');
+  }
+
+  function testPluginInstanceDerivativeFetchingViaPluginClass() {
+    $plugin_definition = $this->TestPluginType->getPluginDefinition('scotch:test1');
+    $plugin = $this->TestPluginType->createPluginInstance('scotch:test1', $plugin_definition);
+    $this->assertEqual($plugin->string(), 'Test String 1', 'Plugin derivative instance 1 returns the proper string');
+
+    $plugin_definition = $this->TestPluginType->getPluginDefinition('scotch:test2');
+    $plugin = $this->TestPluginType->createPluginInstance('scotch:test2', $plugin_definition);
+    $this->assertEqual($plugin->string(), 'Test String 2', 'Plugin derivative instance 2 returns the proper string');
+  }
+
+  function testPluginEmptyDerivativeInstanceFetching() {
+    try {
+      // This test is working against a plugin definition which does not
+      // use_base => TRUE, and so it should throw an exception.
+      $plugin = $this->TestPluginType->createPluginInstance('wine');
+      $this->fail('Drupal\Component\Plugin\PluginException expected');
+    }
+    catch (Exception $e) {
+      if ($e instanceof Drupal\Component\Plugin\PluginException) {
+        $this->pass('Drupal\Component\Plugin\PluginException expected and caught.');
+      }
+      else {
+        $this->fail('Drupal\Component\Plugin\PluginException expected');
+      }
+    }
+    try {
+      // This test is working against a plugin definition which does
+      // use_base => TRUE, and so it should not throw an exception.
+      $plugin = $this->TestPluginType->createPluginInstance('beer');
+      $this->pass('Drupal\Component\Plugin\PluginException not thrown');
+    }
+    catch (Exception $e) {
+      $this->fail('An unexpected exception was thrown.');
+    }
+  }
+
+  function testPluginGetDefinitions() {
+    $definitions = $this->TestPluginType->getPluginDefinitions();
+    $expected = array (
+      'coolaid',
+      'beer:test1',
+      'beer:test2',
+      'beer',
+      'wine:test1',
+      'wine:test2',
+      'scotch:test1',
+      'scotch:test2',
+    );
+    $this->assertIdentical($expected, array_keys($definitions), 'All plugin ids that were expected were found.');
   }
 }
