diff --git a/core/lib/Drupal/Component/Plugin/Derivative/DeriverBase.php b/core/lib/Drupal/Component/Plugin/Derivative/DeriverBase.php
index f989bf6..b2273d0 100644
--- a/core/lib/Drupal/Component/Plugin/Derivative/DeriverBase.php
+++ b/core/lib/Drupal/Component/Plugin/Derivative/DeriverBase.php
@@ -15,7 +15,9 @@
   /**
    * List of derivative definitions.
    *
-   * @var array
+   * @var array[]
+   *   Keys are base plugin IDs and values are arrays of which keys are plugin
+   *   IDs and values are derivative definitions.
    */
   protected $derivatives = array();
 
@@ -23,17 +25,14 @@
    * {@inheritdoc}
    */
   public function getDerivativeDefinition($derivative_id, $base_plugin_definition) {
-    if (!empty($this->derivatives) && !empty($this->derivatives[$derivative_id])) {
-      return $this->derivatives[$derivative_id];
-    }
-    $this->getDerivativeDefinitions($base_plugin_definition);
-    return $this->derivatives[$derivative_id];
+    $definitions = $this->getDerivativeDefinitions($base_plugin_definition);
+    return isset($definitions[$derivative_id]) ? $definitions[$derivative_id] : NULL;
   }
 
   /**
    * {@inheritdoc}
    */
   public function getDerivativeDefinitions($base_plugin_definition) {
-    return $this->derivatives;
+    return isset($this->derivatives[$base_plugin_definition['id']]) ? $this->derivatives[$base_plugin_definition['id']] : [];
   }
 }
diff --git a/core/lib/Drupal/Core/Entity/Plugin/Derivative/SelectionBase.php b/core/lib/Drupal/Core/Entity/Plugin/Derivative/SelectionBase.php
index 0752494..cf61d12 100644
--- a/core/lib/Drupal/Core/Entity/Plugin/Derivative/SelectionBase.php
+++ b/core/lib/Drupal/Core/Entity/Plugin/Derivative/SelectionBase.php
@@ -53,11 +53,16 @@ public static function create(ContainerInterface $container, $base_plugin_id) {
    * {@inheritdoc}
    */
   public function getDerivativeDefinitions($base_plugin_definition) {
-    foreach ($this->entityManager->getDefinitions() as $entity_type_id => $entity_type) {
-      $this->derivatives[$entity_type_id] = $base_plugin_definition;
-      $this->derivatives[$entity_type_id]['entity_types'] = array($entity_type_id);
-      $this->derivatives[$entity_type_id]['label'] = t('@entity_type selection', array('@entity_type' => $entity_type->getLabel()));
-      $this->derivatives[$entity_type_id]['base_plugin_label'] = (string) $base_plugin_definition['label'];
+    if (!array_key_exists($base_plugin_definition['id'], $this->derivatives)) {
+      $derivative_definitions = [];
+      foreach ($this->entityManager->getDefinitions() as $entity_type_id => $entity_type) {
+        $derivative_definitions[$entity_type_id] = $base_plugin_definition;
+        $derivative_definitions[$entity_type_id]['entity_types'] = array($entity_type_id);
+        $derivative_definitions[$entity_type_id]['label'] = t('@entity_type selection',
+          array('@entity_type' => $entity_type->getLabel()));
+        $derivative_definitions[$entity_type_id]['base_plugin_label'] = (string) $base_plugin_definition['label'];
+      }
+      $this->derivatives[$base_plugin_definition['id']] = $derivative_definitions;
     }
     return parent::getDerivativeDefinitions($base_plugin_definition);
   }
diff --git a/core/modules/block_content/src/Plugin/Derivative/BlockContent.php b/core/modules/block_content/src/Plugin/Derivative/BlockContent.php
index 115f2a4..2a84dfc 100644
--- a/core/modules/block_content/src/Plugin/Derivative/BlockContent.php
+++ b/core/modules/block_content/src/Plugin/Derivative/BlockContent.php
@@ -48,14 +48,18 @@ public static function create(ContainerInterface $container, $base_plugin_id) {
    * {@inheritdoc}
    */
   public function getDerivativeDefinitions($base_plugin_definition) {
-    $block_contents = $this->blockContentStorage->loadMultiple();
-    /** @var $block_content \Drupal\block_content\Entity\BlockContent */
-    foreach ($block_contents as $block_content) {
-      $this->derivatives[$block_content->uuid()] = $base_plugin_definition;
-      $this->derivatives[$block_content->uuid()]['admin_label'] = $block_content->label();
-      $this->derivatives[$block_content->uuid()]['config_dependencies']['content'] = array(
-        $block_content->getConfigDependencyName()
-      );
+    if (!array_key_exists($base_plugin_definition['id'], $this->derivatives)) {
+      $derivative_definitions = [];
+      $block_contents = $this->blockContentStorage->loadMultiple();
+      /** @var $block_content \Drupal\block_content\Entity\BlockContent */
+      foreach ($block_contents as $block_content) {
+        $derivative_definitions[$block_content->uuid()] = $base_plugin_definition;
+        $derivative_definitions[$block_content->uuid()]['admin_label'] = $block_content->label();
+        $derivative_definitions[$block_content->uuid()]['config_dependencies']['content'] = array(
+          $block_content->getConfigDependencyName()
+        );
+      }
+      $this->derivatives[$base_plugin_definition['id']] = $derivative_definitions;
     }
     return parent::getDerivativeDefinitions($base_plugin_definition);
   }
diff --git a/core/modules/config_translation/src/Plugin/Derivative/ConfigTranslationContextualLinks.php b/core/modules/config_translation/src/Plugin/Derivative/ConfigTranslationContextualLinks.php
index 8ecde5e..b6542c0 100644
--- a/core/modules/config_translation/src/Plugin/Derivative/ConfigTranslationContextualLinks.php
+++ b/core/modules/config_translation/src/Plugin/Derivative/ConfigTranslationContextualLinks.php
@@ -48,24 +48,27 @@ public static function create(ContainerInterface $container, $base_plugin_id) {
    * {@inheritdoc}
    */
   public function getDerivativeDefinitions($base_plugin_definition) {
-    // Create contextual links for all mappers.
-    $mappers = $this->mapperManager->getMappers();
-    foreach ($mappers as $plugin_id => $mapper) {
-      // @todo Contextual groups do not map to entity types in a predictable
-      //   way. See https://www.drupal.org/node/2134841 to make them
-      //   predictable.
-      $group_name = $mapper->getContextualLinkGroup();
-      if (empty($group_name)) {
-        continue;
-      }
+    if (!array_key_exists($base_plugin_definition['id'], $this->derivatives)) {
+      $derivative_definitions = [];
+      // Create contextual links for all mappers.
+      $mappers = $this->mapperManager->getMappers();
+      foreach ($mappers as $plugin_id => $mapper) {
+        // @todo Contextual groups do not map to entity types in a predictable
+        //   way. See https://www.drupal.org/node/2134841 to make them predictable.
+        $group_name = $mapper->getContextualLinkGroup();
+        if (empty($group_name)) {
+          continue;
+        }
 
-      /** @var \Drupal\config_translation\ConfigMapperInterface $mapper */
-      $route_name = $mapper->getOverviewRouteName();
-      $this->derivatives[$route_name] = $base_plugin_definition;
-      $this->derivatives[$route_name]['config_translation_plugin_id'] = $plugin_id;
-      $this->derivatives[$route_name]['class'] = '\Drupal\config_translation\Plugin\Menu\ContextualLink\ConfigTranslationContextualLink';
-      $this->derivatives[$route_name]['route_name'] = $route_name;
-      $this->derivatives[$route_name]['group'] = $group_name;
+        /** @var \Drupal\config_translation\ConfigMapperInterface $mapper */
+        $route_name = $mapper->getOverviewRouteName();
+        $derivative_definitions[$route_name] = $base_plugin_definition;
+        $derivative_definitions[$route_name]['config_translation_plugin_id'] = $plugin_id;
+        $derivative_definitions[$route_name]['class'] = '\Drupal\config_translation\Plugin\Menu\ContextualLink\ConfigTranslationContextualLink';
+        $derivative_definitions[$route_name]['route_name'] = $route_name;
+        $derivative_definitions[$route_name]['group'] = $group_name;
+      }
+      $this->derivatives[$base_plugin_definition['id']] = $derivative_definitions;
     }
     return parent::getDerivativeDefinitions($base_plugin_definition);
   }
diff --git a/core/modules/config_translation/src/Plugin/Derivative/ConfigTranslationLocalTasks.php b/core/modules/config_translation/src/Plugin/Derivative/ConfigTranslationLocalTasks.php
index c36f72d..76d0e3a 100644
--- a/core/modules/config_translation/src/Plugin/Derivative/ConfigTranslationLocalTasks.php
+++ b/core/modules/config_translation/src/Plugin/Derivative/ConfigTranslationLocalTasks.php
@@ -58,18 +58,22 @@ public static function create(ContainerInterface $container, $base_plugin_id) {
    * {@inheritdoc}
    */
   public function getDerivativeDefinitions($base_plugin_definition) {
-    $mappers = $this->mapperManager->getMappers();
-    foreach ($mappers as $plugin_id => $mapper) {
-      /** @var \Drupal\config_translation\ConfigMapperInterface $mapper */
-      $route_name = $mapper->getOverviewRouteName();
-      $base_route = $mapper->getBaseRouteName();
-      if (!empty($base_route)) {
-        $this->derivatives[$route_name] = $base_plugin_definition;
-        $this->derivatives[$route_name]['config_translation_plugin_id'] = $plugin_id;
-        $this->derivatives[$route_name]['class'] = '\Drupal\config_translation\Plugin\Menu\LocalTask\ConfigTranslationLocalTask';
-        $this->derivatives[$route_name]['route_name'] = $route_name;
-        $this->derivatives[$route_name]['base_route'] = $base_route;
+    if (!array_key_exists($base_plugin_definition['id'], $this->derivatives)) {
+      $derivative_definitions = [];
+      $mappers = $this->mapperManager->getMappers();
+      foreach ($mappers as $plugin_id => $mapper) {
+        /** @var \Drupal\config_translation\ConfigMapperInterface $mapper */
+        $route_name = $mapper->getOverviewRouteName();
+        $base_route = $mapper->getBaseRouteName();
+        if (!empty($base_route)) {
+          $derivative_definitions[$route_name] = $base_plugin_definition;
+          $derivative_definitions[$route_name]['config_translation_plugin_id'] = $plugin_id;
+          $derivative_definitions[$route_name]['class'] = '\Drupal\config_translation\Plugin\Menu\LocalTask\ConfigTranslationLocalTask';
+          $derivative_definitions[$route_name]['route_name'] = $route_name;
+          $derivative_definitions[$route_name]['base_route'] = $base_route;
+        }
       }
+      $this->derivatives[$base_plugin_definition['id']] = $derivative_definitions;
     }
     return parent::getDerivativeDefinitions($base_plugin_definition);
   }
diff --git a/core/modules/content_translation/src/Plugin/Derivative/ContentTranslationContextualLinks.php b/core/modules/content_translation/src/Plugin/Derivative/ContentTranslationContextualLinks.php
index 9acf394..d16536e 100644
--- a/core/modules/content_translation/src/Plugin/Derivative/ContentTranslationContextualLinks.php
+++ b/core/modules/content_translation/src/Plugin/Derivative/ContentTranslationContextualLinks.php
@@ -50,11 +50,15 @@ public static function create(ContainerInterface $container, $base_plugin_id) {
    * {@inheritdoc}
    */
   public function getDerivativeDefinitions($base_plugin_definition) {
-    // Create contextual links for translatable entity types.
-    foreach ($this->contentTranslationManager->getSupportedEntityTypes() as $entity_type_id => $entity_type) {
-      $this->derivatives[$entity_type_id]['title'] = t('Translate');
-      $this->derivatives[$entity_type_id]['route_name'] = "entity.$entity_type_id.content_translation_overview";
-      $this->derivatives[$entity_type_id]['group'] = $entity_type_id;
+    if (!array_key_exists($base_plugin_definition['id'], $this->derivatives)) {
+      $derivative_definitions = [];
+      // Create contextual links for translatable entity types.
+      foreach ($this->contentTranslationManager->getSupportedEntityTypes() as $entity_type_id => $entity_type) {
+        $derivative_definitions[$entity_type_id]['title'] = t('Translate');
+        $derivative_definitions[$entity_type_id]['route_name'] = "entity.$entity_type_id.content_translation_overview";
+        $derivative_definitions[$entity_type_id]['group'] = $entity_type_id;
+      }
+      $this->derivatives[$base_plugin_definition['id']] = $derivative_definitions;
     }
     return parent::getDerivativeDefinitions($base_plugin_definition);
   }
diff --git a/core/modules/content_translation/src/Plugin/Derivative/ContentTranslationLocalTasks.php b/core/modules/content_translation/src/Plugin/Derivative/ContentTranslationLocalTasks.php
index 995de59..661a10c 100644
--- a/core/modules/content_translation/src/Plugin/Derivative/ContentTranslationLocalTasks.php
+++ b/core/modules/content_translation/src/Plugin/Derivative/ContentTranslationLocalTasks.php
@@ -58,18 +58,22 @@ public static function create(ContainerInterface $container, $base_plugin_id) {
    * {@inheritdoc}
    */
   public function getDerivativeDefinitions($base_plugin_definition) {
-    // Create tabs for all possible entity types.
-    foreach ($this->contentTranslationManager->getSupportedEntityTypes() as $entity_type_id => $entity_type) {
-      // Find the route name for the translation overview.
-      $translation_route_name = "entity.$entity_type_id.content_translation_overview";
+    if (!array_key_exists($base_plugin_definition['id'], $this->derivatives)) {
+      $derivative_definitions = [];
+      // Create tabs for all possible entity types.
+      foreach ($this->contentTranslationManager->getSupportedEntityTypes() as $entity_type_id => $entity_type) {
+        // Find the route name for the translation overview.
+        $translation_route_name = "entity.$entity_type_id.content_translation_overview";
 
-      $base_route_name = "entity.$entity_type_id.canonical";
-      $this->derivatives[$translation_route_name] = array(
-        'entity_type' => $entity_type_id,
-        'title' => 'Translate',
-        'route_name' => $translation_route_name,
-        'base_route' => $base_route_name,
-      ) + $base_plugin_definition;
+        $base_route_name = "entity.$entity_type_id.canonical";
+        $derivative_definitions[$translation_route_name] = array(
+            'entity_type' => $entity_type_id,
+            'title' => 'Translate',
+            'route_name' => $translation_route_name,
+            'base_route' => $base_route_name,
+          ) + $base_plugin_definition;
+      }
+      $this->derivatives[$base_plugin_definition['id']] = $derivative_definitions;
     }
     return parent::getDerivativeDefinitions($base_plugin_definition);
   }
diff --git a/core/modules/language/src/Plugin/Derivative/LanguageBlock.php b/core/modules/language/src/Plugin/Derivative/LanguageBlock.php
index 3c54c25..7c6e9a5 100644
--- a/core/modules/language/src/Plugin/Derivative/LanguageBlock.php
+++ b/core/modules/language/src/Plugin/Derivative/LanguageBlock.php
@@ -19,20 +19,25 @@ class LanguageBlock extends DeriverBase {
    * {@inheritdoc}
    */
   public function getDerivativeDefinitions($base_plugin_definition) {
-    $language_manager = \Drupal::languageManager();
-
-    if ($language_manager instanceof ConfigurableLanguageManagerInterface) {
-      $info = $language_manager->getDefinedLanguageTypesInfo();
-      $configurable_types = $language_manager->getLanguageTypes();
-      foreach ($configurable_types as $type) {
-        $this->derivatives[$type] = $base_plugin_definition;
-        $this->derivatives[$type]['admin_label'] = t('Language switcher (!type)', array('!type' => $info[$type]['name']));
-      }
-      // If there is just one configurable type then change the title of the
-      // block.
-      if (count($configurable_types) == 1) {
-        $this->derivatives[reset($configurable_types)]['admin_label'] = t('Language switcher');
+    if (!array_key_exists($base_plugin_definition['id'], $this->derivatives)) {
+      $derivative_definitions = [];
+      $language_manager = \Drupal::languageManager();
+
+      if ($language_manager instanceof ConfigurableLanguageManagerInterface) {
+        $info = $language_manager->getDefinedLanguageTypesInfo();
+        $configurable_types = $language_manager->getLanguageTypes();
+        foreach ($configurable_types as $type) {
+          $derivative_definitions[$type] = $base_plugin_definition;
+          $derivative_definitions[$type]['admin_label'] = t('Language switcher (!type)',
+            array('!type' => $info[$type]['name']));
+        }
+        // If there is just one configurable type then change the title of the
+        // block.
+        if (count($configurable_types) == 1) {
+          $derivative_definitions[reset($configurable_types)]['admin_label'] = t('Language switcher');
+        }
       }
+      $this->derivatives[$base_plugin_definition['id']] = $derivative_definitions;
     }
 
     return parent::getDerivativeDefinitions($base_plugin_definition);
diff --git a/core/modules/system/tests/modules/entity_test/src/Plugin/Derivative/EntityTestLocalTasks.php b/core/modules/system/tests/modules/entity_test/src/Plugin/Derivative/EntityTestLocalTasks.php
index e4f8e49..5c46686 100644
--- a/core/modules/system/tests/modules/entity_test/src/Plugin/Derivative/EntityTestLocalTasks.php
+++ b/core/modules/system/tests/modules/entity_test/src/Plugin/Derivative/EntityTestLocalTasks.php
@@ -18,19 +18,22 @@ class EntityTestLocalTasks extends DeriverBase {
    * {@inheritdoc}
    */
   public function getDerivativeDefinitions($base_plugin_definition) {
-    $this->derivatives = array();
-    $types = entity_test_entity_types(ENTITY_TEST_TYPES_ROUTING);
-
-    foreach($types as $entity_type) {
-      $this->derivatives[$entity_type . '.canonical'] = array();
-      $this->derivatives[$entity_type . '.canonical']['base_route'] = "entity.$entity_type.canonical";
-      $this->derivatives[$entity_type . '.canonical']['route_name'] = "entity.$entity_type.canonical";
-      $this->derivatives[$entity_type . '.canonical']['title'] = 'View';
-
-      $this->derivatives[$entity_type . '.edit'] = array();
-      $this->derivatives[$entity_type . '.edit']['base_route'] = "entity.$entity_type.canonical";
-      $this->derivatives[$entity_type . '.edit']['route_name'] = "entity.$entity_type.edit_form";
-      $this->derivatives[$entity_type . '.edit']['title'] = 'Edit';
+    if (!array_key_exists($base_plugin_definition['id'], $this->derivatives)) {
+      $derivative_definitions = [];
+      $types = entity_test_entity_types(ENTITY_TEST_TYPES_ROUTING);
+
+      foreach ($types as $entity_type) {
+        $derivative_definitions[$entity_type . '.canonical'] = array();
+        $derivative_definitions[$entity_type . '.canonical']['base_route'] = "entity.$entity_type.canonical";
+        $derivative_definitions[$entity_type . '.canonical']['route_name'] = "entity.$entity_type.canonical";
+        $derivative_definitions[$entity_type . '.canonical']['title'] = 'View';
+
+        $derivative_definitions[$entity_type . '.edit'] = array();
+        $derivative_definitions[$entity_type . '.edit']['base_route'] = "entity.$entity_type.canonical";
+        $derivative_definitions[$entity_type . '.edit']['route_name'] = "entity.$entity_type.edit_form";
+        $derivative_definitions[$entity_type . '.edit']['title'] = 'Edit';
+      }
+      $this->derivatives[$base_plugin_definition['id']] = $derivative_definitions;
     }
 
     return parent::getDerivativeDefinitions($base_plugin_definition);
diff --git a/core/modules/views/src/Plugin/Derivative/DefaultWizardDeriver.php b/core/modules/views/src/Plugin/Derivative/DefaultWizardDeriver.php
index f7610f2..005b9bf 100644
--- a/core/modules/views/src/Plugin/Derivative/DefaultWizardDeriver.php
+++ b/core/modules/views/src/Plugin/Derivative/DefaultWizardDeriver.php
@@ -20,19 +20,22 @@ class DefaultWizardDeriver extends DeriverBase {
    * {@inheritdoc}
    */
   public function getDerivativeDefinitions($base_plugin_definition) {
-    $views_data = Views::viewsData();
-    $base_tables = array_keys($views_data->fetchBaseTables());
-    $this->derivatives = array();
-    foreach ($base_tables as $table) {
-      $views_info = $views_data->get($table);
-      if (empty($views_info['table']['wizard_id'])) {
-        $this->derivatives[$table] = array(
-          'id' => 'standard',
-          'base_table' => $table,
-          'title' => $views_info['table']['base']['title'],
-          'class' => 'Drupal\views\Plugin\views\wizard\Standard'
-        );
+    if (!array_key_exists($base_plugin_definition['id'], $this->derivatives)) {
+      $derivative_definitions = [];
+      $views_data = Views::viewsData();
+      $base_tables = array_keys($views_data->fetchBaseTables());
+      foreach ($base_tables as $table) {
+        $views_info = $views_data->get($table);
+        if (empty($views_info['table']['wizard_id'])) {
+          $derivative_definitions[$table] = array(
+            'id' => 'standard',
+            'base_table' => $table,
+            'title' => $views_info['table']['base']['title'],
+            'class' => 'Drupal\views\Plugin\views\wizard\Standard'
+          );
+        }
       }
+      $this->derivatives[$base_plugin_definition['id']] = $derivative_definitions;
     }
     return parent::getDerivativeDefinitions($base_plugin_definition);
   }
diff --git a/core/tests/Drupal/Tests/Component/Plugin/Derivative/DeriverBaseTest.php b/core/tests/Drupal/Tests/Component/Plugin/Derivative/DeriverBaseTest.php
new file mode 100644
index 0000000..6adfa11
--- /dev/null
+++ b/core/tests/Drupal/Tests/Component/Plugin/Derivative/DeriverBaseTest.php
@@ -0,0 +1,77 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Tests\Component\Plugin\Derivative\DeriverBaseTest.
+ */
+
+namespace Drupal\Tests\Component\Plugin\Derivative;
+
+use Drupal\Component\Plugin\Derivative\DeriverBase;
+use Drupal\Tests\UnitTestCase;
+
+/**
+ * @coversDefaultClass Drupal\Component\Plugin\Derivative\DeriverBase
+ *
+ * @group Plugin
+ */
+class DeriverBaseTest extends UnitTestCase {
+
+  /**
+   * Provides data to self::testGetDerivativeDefinition().
+   *
+   * @return array
+   *   - Derivatives definition array to set into ::$derivatives.
+   *   - The derivative ID to query for within the derivatives array. This value
+   *     is passed to getDerivativeDefinition().
+   */
+  public function providerGetDerivativeDefinition() {
+    $derivative_id = $this->randomMachineName();
+    $base_id = $this->randomMachineName();
+
+    $derivative_definitions = [
+      $base_id => [
+        $derivative_id => [
+          'id' => $this->randomMachineName() . ':' . $derivative_id,
+        ],
+      ],
+    ];
+
+    $base_definition = [
+      'id' => $base_id,
+    ];
+
+    return [
+      [$derivative_definitions[$base_id][$derivative_id], $derivative_definitions, $derivative_id, $base_definition],
+      [NULL, $derivative_definitions, $this->randomMachineName(), $base_definition],
+    ];
+  }
+
+  /**
+   * @covers ::getDerivativeDefinition
+   * @dataProvider providerGetDerivativeDefinition
+   */
+  public function testGetDerivativeDefinition($expected_derivative_definition, $derivative_definitions, $derivative_id, $base_definition) {
+    $deriver = new DeriverBaseTestDeriverBaseDummy($derivative_definitions);
+
+    $derivative_definition = $deriver->getDerivativeDefinition($derivative_id, $base_definition);
+    $this->assertSame($expected_derivative_definition, $derivative_definition);
+  }
+
+}
+
+/**
+ * Provides DeriverBase with settable derivatives.
+ */
+class DeriverBaseTestDeriverBaseDummy extends DeriverBase {
+
+  /**
+   * Constructs a new instance.
+   *
+   * @param mixed[] $derivative_definitions
+   */
+  public function __construct(array $derivative_definitions) {
+    $this->derivatives = $derivative_definitions;
+  }
+
+}
