diff --git a/core/lib/Drupal/Component/Plugin/Derivative/DerivativeInterface.php b/core/lib/Drupal/Component/Plugin/Derivative/DerivativeInterface.php
index 281a4ca..748715f 100644
--- a/core/lib/Drupal/Component/Plugin/Derivative/DerivativeInterface.php
+++ b/core/lib/Drupal/Component/Plugin/Derivative/DerivativeInterface.php
@@ -1,36 +1,45 @@
 <?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.
+   *
+   * @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/Discovery/DerivativeAwareDiscovery.php b/core/lib/Drupal/Component/Plugin/Discovery/DerivativeAwareDiscovery.php
new file mode 100644
index 0000000..dfe36bf
--- /dev/null
+++ b/core/lib/Drupal/Component/Plugin/Discovery/DerivativeAwareDiscovery.php
@@ -0,0 +1,79 @@
+<?php
+
+/**
+ * @file
+ * ...
+ */
+
+namespace Drupal\Component\Plugin\Discovery;
+
+abstract class DerivativeAwareDiscovery implements DiscoveryInterface {
+
+  protected $derivativeFetchers = array();
+
+  /**
+   * Implements DiscoveryInterface::getPluginDefinition().
+   */
+  public function getPluginDefinition($pluginId) {
+    $basePluginId = ($pos = strpos($pluginId, ':')) ? substr($pluginId, 0, $pos) : $pluginId;
+    $baseDefinition = $this->getBasePluginDefinition($basePluginId);
+    $derivativeFetcher = $this->getDerivativeFetcher($basePluginId, $baseDefinition);
+    if ($pluginId == $basePluginId) {
+      if (isset($derivativeFetcher)) {
+        // Some plugins allow independent existence of the base plugin
+        // (derivativeId = NULL), some do not (by returning a NULL definition).
+        $definition = $derivativeFetcher->getDerivativeDefinition(NULL, $baseDefinition);
+      }
+      else {
+        $definition = $baseDefinition;
+      }
+    }
+    elseif (isset($derivativeFetcher)) {
+      $derivativeId = substr($pluginId, strlen($basePluginId)+1);
+      $definition = $derivativeFetcher->getDerivativeDefinition($derivativeId, $baseDefinition);
+    }
+    else {
+      $definition = NULL;
+    }
+    return $definition;
+  }
+
+  /**
+   * Implements DiscoveryInterface::getPluginDefinitions().
+   */
+  public function getPluginDefinitions() {
+    $definitions = array();
+    $baseDefinitions = $this->getBasePluginDefinitions();
+    foreach ($baseDefinitions as $basePluginId => $baseDefinition) {
+      $derivativeFetcher = $this->getDerivativeFetcher($basePluginId, $baseDefinition);
+      if (isset($derivativeFetcher)) {
+        $derivativeDefinitions = $derivativeFetcher->getDerivativeDefinitions($baseDefinition);
+        foreach ($derivativeDefinitions as $derivativeId => $definition) {
+          $pluginId = strlen($derivativeId) ? "$basePluginId:$derivativeId" : $basePluginId;
+          $definitions[$pluginId] = $definition;
+        }
+      }
+      else {
+        $definitions[$basePluginId] = $baseDefinition;
+      }
+    }
+    return $definitions;
+  }
+
+  /**
+   * Returns the object that gets a base plugin's derivatives.
+   */
+  protected function getDerivativeFetcher($basePluginId, $baseDefinition) {
+    if (!isset($this->derivativeFetchers[$basePluginId])) {
+      $this->derivativeFetchers[$basePluginId] = FALSE;
+      if (isset($baseDefinition['derivative'])) {
+        $class = $baseDefinition['derivative'];
+        $this->derivativeFetchers[$basePluginId] = new $class($basePluginId);
+      }
+    }
+    return $this->derivativeFetchers[$basePluginId] ?: NULL;
+  }
+
+  abstract protected function getBasePluginDefinition($basePluginId);
+  abstract protected function getBasePluginDefinitions();
+}
diff --git a/core/lib/Drupal/Component/Plugin/Discovery/StaticDiscovery.php b/core/lib/Drupal/Component/Plugin/Discovery/StaticDiscovery.php
index 1d787c3..7e8fa54 100644
--- a/core/lib/Drupal/Component/Plugin/Discovery/StaticDiscovery.php
+++ b/core/lib/Drupal/Component/Plugin/Discovery/StaticDiscovery.php
@@ -9,22 +9,22 @@ namespace Drupal\Component\Plugin\Discovery;
 /**
  *
  */
-class StaticDiscovery implements DiscoveryInterface {
+class StaticDiscovery extends DerivativeAwareDiscovery {
 
   protected $plugin_definitions = array();
 
   /**
-   * Implements DiscoveryInterface::getPluginDefinition().
+   * Implements DerivativeAwareDiscovery::getBasePluginDefinition().
    */
-  public function getPluginDefinition($plugin) {
-    return isset($this->plugin_definitions[$plugin]) ? $this->plugin_definitions[$plugin] : array();
+  public function getBasePluginDefinition($basePluginId) {
+    return $this->plugin_definitions[$basePluginId];
   }
 
   /**
-   * Implements DiscoveryInterface::getPluginDefinitions().
+   * Implements DerivativeAwareDiscovery::getBasePluginDefinitions().
    */
-  public function getPluginDefinitions() {
-    return isset($this->plugin_definitions) ? $this->plugin_definitions : array();
+  public function getBasePluginDefinitions() {
+    return $this->plugin_definitions;
   }
 
   /**
diff --git a/core/lib/Drupal/Component/Plugin/Factory/DefaultFactory.php b/core/lib/Drupal/Component/Plugin/Factory/DefaultFactory.php
index 2d81ed9..efe83e0 100644
--- a/core/lib/Drupal/Component/Plugin/Factory/DefaultFactory.php
+++ b/core/lib/Drupal/Component/Plugin/Factory/DefaultFactory.php
@@ -38,7 +38,7 @@ class DefaultFactory implements FactoryInterface {
       $params = $reflector->getMethod('__construct')->getParameters();
       $args = array();
       foreach ($params as $param) {
-        $args[$param->name] = $configuration[$param->name];
+        $args[$param->name] = isset($configuration[$param->name]) ? $configuration[$param->name] : NULL;
       }
       $instance = $reflector->newInstanceArgs($args);
     }
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/Core/Plugin/Discovery/ConfigDiscovery.php b/core/lib/Drupal/Core/Plugin/Discovery/ConfigDiscovery.php
index c160b1a..ca574e2 100644
--- a/core/lib/Drupal/Core/Plugin/Discovery/ConfigDiscovery.php
+++ b/core/lib/Drupal/Core/Plugin/Discovery/ConfigDiscovery.php
@@ -6,9 +6,9 @@
  */
 
 namespace Drupal\Core\Plugin\Discovery;
-use Drupal\Component\Plugin\Discovery\DiscoveryInterface;
+use Drupal\Component\Plugin\Discovery\DerivativeAwareDiscovery;
 
-class ConfigDiscovery implements DiscoveryInterface {
+class ConfigDiscovery extends DerivativeAwareDiscovery {
 
   protected $definition_root;
 
@@ -17,33 +17,21 @@ class ConfigDiscovery implements DiscoveryInterface {
   }
 
   /**
-   * Implements DicoveryInterface::getPluginDefinition().
+   * Implements DerivativeAwareDiscovery::getBasePluginDefinition().
    */
-  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 $config;
+  public function getBasePluginDefinition($basePluginId) {
+    return config("{$this->definition_root}.$basePluginId")->get();
   }
 
   /**
-   * Implements DicoveryInterface::getPluginDefinitions().
+   * Implements DerivativeAwareDiscovery::getBasePluginDefinitions().
    */
-  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] = $derivative;
-        }
-        unset($plugins[$plugin_id]);
-      }
+  public function getBasePluginDefinitions() {
+    $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);
+      $definitions[$basePluginId] = config($config_name)->get();
     }
-    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/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 74799db..d7527d7 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
@@ -18,6 +18,17 @@ class TestPluginType extends PluginType {
       '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->factory = new DefaultFactory($this->discovery, 'class');
     $this->mapper = new DefaultMapper($this->discovery, $this->factory);
   }
diff --git a/core/modules/system/tests/plugins.test b/core/modules/system/tests/plugins.test
index 0966593..a06a437 100644
--- a/core/modules/system/tests/plugins.test
+++ b/core/modules/system/tests/plugins.test
@@ -68,7 +68,67 @@ 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 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',
+    );
+    $this->assertIdentical($expected, array_keys($definitions), 'All plugin ids that were expected were found.');
   }
 }
