diff --git a/core/lib/Drupal/Component/Plugin/DerivativeInspectionInterface.php b/core/lib/Drupal/Component/Plugin/DerivativeInspectionInterface.php
new file mode 100644
index 0000000..4dbd9d5
--- /dev/null
+++ b/core/lib/Drupal/Component/Plugin/DerivativeInspectionInterface.php
@@ -0,0 +1,31 @@
+<?php
+
+/**
+ * @file
+ * Contains Drupal\Component\Plugin\DerivativeInspectionInterface.
+ */
+
+namespace Drupal\Component\Plugin;
+
+/**
+ * Provides a plugin interface for providing derivative metadata inspection.
+ */
+interface DerivativeInspectionInterface {
+
+  /**
+   * Returns the base_plugin_id of the plugin instance.
+   *
+   * @return string
+   *   The base_plugin_id of the plugin instance.
+   */
+  public function getBasePluginId();
+
+  /**
+   * Returns the derivative_id of the plugin instance.
+   *
+   * @return string|null
+   *   The derivative_id of the plugin instance NULL otherwise.
+   */
+  public function getDerivativeId();
+
+}
diff --git a/core/lib/Drupal/Component/Plugin/PluginBase.php b/core/lib/Drupal/Component/Plugin/PluginBase.php
index fb36f2a..8c3f274 100644
--- a/core/lib/Drupal/Component/Plugin/PluginBase.php
+++ b/core/lib/Drupal/Component/Plugin/PluginBase.php
@@ -9,7 +9,7 @@
 /**
  * Base class for plugins wishing to support metadata inspection.
  */
-abstract class PluginBase implements PluginInspectionInterface {
+abstract class PluginBase implements PluginInspectionInterface, DerivativeInspectionInterface {
 
   /**
    * The plugin_id.
@@ -58,6 +58,29 @@ public function getPluginId() {
   /**
    * {@inheritdoc}
    */
+  public function getBasePluginId() {
+    $plugin_id = $this->getPluginId();
+    if (strpos($plugin_id, ':')) {
+      list($plugin_id) = explode(':', $plugin_id, 2);
+    }
+    return $plugin_id;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getDerivativeId() {
+    $plugin_id = $this->getPluginId();
+    $derivative_id = NULL;
+    if (strpos($plugin_id, ':')) {
+      list(, $derivative_id) = explode(':', $plugin_id, 2);
+    }
+    return $derivative_id;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
   public function getPluginDefinition() {
     return $this->pluginDefinition;
   }
diff --git a/core/lib/Drupal/Component/Plugin/PluginInspectionInterface.php b/core/lib/Drupal/Component/Plugin/PluginInspectionInterface.php
index 31e5e46..71fee3b 100644
--- a/core/lib/Drupal/Component/Plugin/PluginInspectionInterface.php
+++ b/core/lib/Drupal/Component/Plugin/PluginInspectionInterface.php
@@ -30,4 +30,5 @@ public function getPluginId();
    *   plugin manager.
    */
   public function getPluginDefinition();
+
 }
diff --git a/core/modules/aggregator/lib/Drupal/aggregator/Plugin/Block/AggregatorFeedBlock.php b/core/modules/aggregator/lib/Drupal/aggregator/Plugin/Block/AggregatorFeedBlock.php
index ca75c64..bb93b63 100644
--- a/core/modules/aggregator/lib/Drupal/aggregator/Plugin/Block/AggregatorFeedBlock.php
+++ b/core/modules/aggregator/lib/Drupal/aggregator/Plugin/Block/AggregatorFeedBlock.php
@@ -65,7 +65,7 @@ public function blockSubmit($form, &$form_state) {
    */
   public function build() {
     // Plugin IDs look something like this: aggregator_feed_block:1.
-    list(, $id) = explode(':', $this->getPluginId());
+    $id = $this->getDerivativeId();
     if ($feed = db_query('SELECT fid, title, block FROM {aggregator_feed} WHERE block <> 0 AND fid = :fid', array(':fid' => $id))->fetchObject()) {
       $result = db_query_range("SELECT * FROM {aggregator_item} WHERE fid = :fid ORDER BY timestamp DESC, iid DESC", 0, $this->configuration['block_count'], array(':fid' => $id));
       $more_link = array(
diff --git a/core/modules/block/block.module b/core/modules/block/block.module
index 18f1c7f..cc7e406 100644
--- a/core/modules/block/block.module
+++ b/core/modules/block/block.module
@@ -523,6 +523,8 @@ function template_preprocess_block(&$variables) {
 
   $variables['configuration'] = $variables['elements']['#configuration'];
   $variables['plugin_id'] = $variables['elements']['#plugin_id'];
+  $variables['base_plugin_id'] = $variables['elements']['#base_plugin_id'];
+  $variables['derivative_plugin_id'] = $variables['elements']['#derivative_plugin_id'];
   $variables['label'] = !empty($variables['configuration']['label_display']) ? $variables['configuration']['label'] : '';
   $variables['content'] = $variables['elements']['content'];
 
diff --git a/core/modules/block/custom_block/lib/Drupal/custom_block/Plugin/Block/CustomBlockBlock.php b/core/modules/block/custom_block/lib/Drupal/custom_block/Plugin/Block/CustomBlockBlock.php
index cdd7016..81e51b9 100644
--- a/core/modules/block/custom_block/lib/Drupal/custom_block/Plugin/Block/CustomBlockBlock.php
+++ b/core/modules/block/custom_block/lib/Drupal/custom_block/Plugin/Block/CustomBlockBlock.php
@@ -121,8 +121,7 @@ public function blockSubmit($form, &$form_state) {
    * {@inheritdoc}
    */
   public function build() {
-    // @todo Clean up when http://drupal.org/node/1874498 lands.
-    list(, $uuid) = explode(':', $this->getPluginId());
+    $uuid = $this->getDerivativeId();
     if ($block = entity_load_by_uuid('custom_block', $uuid)) {
       return entity_view($block, $this->configuration['view_mode']);
     }
diff --git a/core/modules/block/lib/Drupal/block/BlockRenderController.php b/core/modules/block/lib/Drupal/block/BlockRenderController.php
index 57a5d62..892420d 100644
--- a/core/modules/block/lib/Drupal/block/BlockRenderController.php
+++ b/core/modules/block/lib/Drupal/block/BlockRenderController.php
@@ -38,6 +38,8 @@ public function viewMultiple(array $entities = array(), $view_mode = 'full', $la
     foreach ($entities as $entity_id => $entity) {
       $plugin = $entity->getPlugin();
       $plugin_id = $plugin->getPluginId();
+      $base_id = $plugin->getBasePluginId();
+      $derivative_id = $plugin->getDerivativeId();
 
       if ($content = $plugin->build()) {
         $configuration = $plugin->getConfiguration();
@@ -46,6 +48,8 @@ public function viewMultiple(array $entities = array(), $view_mode = 'full', $la
           'content' => $content,
           '#configuration' => $configuration,
           '#plugin_id' => $plugin_id,
+          '#base_plugin_id' => $base_id,
+          '#derivative_plugin_id' => $derivative_id,
         );
         $build[$entity_id]['#configuration']['label'] = check_plain($configuration['label']);
       }
@@ -53,7 +57,6 @@ public function viewMultiple(array $entities = array(), $view_mode = 'full', $la
         $build[$entity_id] = array();
       }
 
-      list($base_id) = explode(':', $plugin_id);
       drupal_alter(array('block_view', "block_view_$base_id"), $build[$entity_id], $plugin);
 
       // @todo Remove after fixing http://drupal.org/node/1989568.
diff --git a/core/modules/block/lib/Drupal/block/Tests/BlockTemplateSuggestionsUnitTest.php b/core/modules/block/lib/Drupal/block/Tests/BlockTemplateSuggestionsUnitTest.php
index 9c2966f..a6611c0 100644
--- a/core/modules/block/lib/Drupal/block/Tests/BlockTemplateSuggestionsUnitTest.php
+++ b/core/modules/block/lib/Drupal/block/Tests/BlockTemplateSuggestionsUnitTest.php
@@ -45,8 +45,11 @@ function testBlockThemeHookSuggestions() {
 
     $variables = array();
     $variables['elements']['#block'] = $block;
-    $variables['elements']['#configuration'] = $block->getPlugin()->getConfiguration();
-    $variables['elements']['#plugin_id'] = $block->get('plugin');
+    $plugin = $block->getPlugin();
+    $variables['elements']['#configuration'] = $plugin->getConfiguration();
+    $variables['elements']['#plugin_id'] = $plugin->getPluginId();
+    $variables['elements']['#base_plugin_id'] = $plugin->getBasePluginId();
+    $variables['elements']['#derivative_plugin_id'] = $plugin->getDerivativeId();
     $variables['elements']['content'] = array();
     // Test adding a class to the block content.
     $variables['content_attributes']['class'][] = 'test-class';
diff --git a/core/modules/language/lib/Drupal/language/Plugin/Block/LanguageBlock.php b/core/modules/language/lib/Drupal/language/Plugin/Block/LanguageBlock.php
index 5279dd6..14ee10a 100644
--- a/core/modules/language/lib/Drupal/language/Plugin/Block/LanguageBlock.php
+++ b/core/modules/language/lib/Drupal/language/Plugin/Block/LanguageBlock.php
@@ -35,7 +35,7 @@ function access() {
   public function build() {
     $build = array();
     $path = drupal_is_front_page() ? '<front>' : current_path();
-    list(, $type) = explode(':', $this->getPluginId());
+    $type = $this->getDerivativeId();
     $links = language_negotiation_get_switch_links($type, $path);
 
     if (isset($links->links)) {
diff --git a/core/modules/menu/lib/Drupal/menu/Plugin/Block/MenuBlock.php b/core/modules/menu/lib/Drupal/menu/Plugin/Block/MenuBlock.php
index 419617c..f5dc03c 100644
--- a/core/modules/menu/lib/Drupal/menu/Plugin/Block/MenuBlock.php
+++ b/core/modules/menu/lib/Drupal/menu/Plugin/Block/MenuBlock.php
@@ -26,7 +26,7 @@ class MenuBlock extends SystemMenuBlock {
    * {@inheritdoc}
    */
   public function build() {
-    list($plugin, $menu) = explode(':', $this->getPluginId());
+    $menu = $this->getDerivativeId();
     return menu_tree($menu);
   }
 
diff --git a/core/modules/system/lib/Drupal/system/Plugin/Block/SystemMenuBlock.php b/core/modules/system/lib/Drupal/system/Plugin/Block/SystemMenuBlock.php
index de823ac..89b9c1a 100644
--- a/core/modules/system/lib/Drupal/system/Plugin/Block/SystemMenuBlock.php
+++ b/core/modules/system/lib/Drupal/system/Plugin/Block/SystemMenuBlock.php
@@ -28,7 +28,7 @@ class SystemMenuBlock extends BlockBase {
    */
   public function access() {
     // @todo The 'Tools' menu should be available to anonymous users.
-    list( , $derivative) = explode(':', $this->getPluginId());
+    $derivative = $this->getDerivativeId();
     return ($GLOBALS['user']->isAuthenticated() || in_array($derivative, array('menu-main', 'menu-tools', 'menu-footer')));
   }
 
@@ -36,7 +36,7 @@ public function access() {
    * {@inheritdoc}
    */
   public function build() {
-    list( , $derivative) = explode(':', $this->getPluginId());
+    $derivative = $this->getDerivativeId();
     // Derivatives are prefixed with 'menu-'.
     $menu = substr($derivative, 5);
     return menu_tree($menu);
diff --git a/core/modules/system/system.module b/core/modules/system/system.module
index dfda891..64ec6d4 100644
--- a/core/modules/system/system.module
+++ b/core/modules/system/system.module
@@ -2282,9 +2282,7 @@ function system_user_timezone(&$form, &$form_state) {
  * Implements hook_preprocess_HOOK() for block.html.twig.
  */
 function system_preprocess_block(&$variables) {
-  // Derive the base plugin ID.
-  list($plugin_id) = explode(':', $variables['plugin_id'] . ':');
-  switch ($plugin_id) {
+  switch ($variables['base_plugin_id']) {
     case 'system_powered_by_block':
       $variables['attributes']['role'] = 'complementary';
       break;
diff --git a/core/modules/views/lib/Drupal/views/Plugin/Block/ViewsBlockBase.php b/core/modules/views/lib/Drupal/views/Plugin/Block/ViewsBlockBase.php
index 10f5dd2..909b030 100644
--- a/core/modules/views/lib/Drupal/views/Plugin/Block/ViewsBlockBase.php
+++ b/core/modules/views/lib/Drupal/views/Plugin/Block/ViewsBlockBase.php
@@ -55,7 +55,7 @@
    */
   public function __construct(array $configuration, $plugin_id, array $plugin_definition, ViewExecutableFactory $executable_factory, EntityStorageControllerInterface $storage_controller) {
     $this->pluginId = $plugin_id;
-    list($plugin, $delta) = explode(':', $this->getPluginId());
+    $delta = $this->getDerivativeId();
     list($name, $this->displayID) = explode('-', $delta, 2);
     // Load the view.
     $view = $storage_controller->load($name);
