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/block/block.module b/core/modules/block/block.module
index 6786cc0..ec29080 100644
--- a/core/modules/block/block.module
+++ b/core/modules/block/block.module
@@ -527,6 +527,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 3731471..8dcc8f5 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 68599a5..aa958d6 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/BlockPreprocessUnitTest.php b/core/modules/block/lib/Drupal/block/Tests/BlockPreprocessTest.php
similarity index 74%
rename from core/modules/block/lib/Drupal/block/Tests/BlockPreprocessUnitTest.php
rename to core/modules/block/lib/Drupal/block/Tests/BlockPreprocessTest.php
index 513fda5..c399879 100644
--- a/core/modules/block/lib/Drupal/block/Tests/BlockPreprocessUnitTest.php
+++ b/core/modules/block/lib/Drupal/block/Tests/BlockPreprocessTest.php
@@ -2,7 +2,7 @@
 
 /**
  * @file
- * Contains \Drupal\block\Tests\BlockPreprocessUnitTest.
+ * Contains \Drupal\block\Tests\BlockPreprocessTest.
  */
 
 namespace Drupal\block\Tests;
@@ -10,9 +10,9 @@
 use Drupal\simpletest\WebTestBase;
 
 /**
- * Unit tests for template_preprocess_block().
+ * Web tests for template_preprocess_block().
  */
-class BlockPreprocessUnitTest extends WebTestBase {
+class BlockPreprocessTest extends WebTestBase {
 
   /**
    * Modules to enable.
@@ -45,9 +45,13 @@ function testBlockClasses() {
 
     $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';
     template_preprocess_block($variables);
diff --git a/core/modules/block/lib/Drupal/block/Tests/BlockTemplateSuggestionsUnitTest.php b/core/modules/block/lib/Drupal/block/Tests/BlockTemplateSuggestionsUnitTest.php
index 6d962ed..604b1a7 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();
     $suggestions = block_theme_suggestions_block($variables);
     $this->assertEqual($suggestions, array('block__system', 'block__system_menu_block', 'block__system_menu_block__admin', 'block__machinename'));
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/menu.module b/core/modules/menu/menu.module
index fe52570..81120ca 100644
--- a/core/modules/menu/menu.module
+++ b/core/modules/menu/menu.module
@@ -334,8 +334,7 @@ function _menu_parents_recurse($tree, $menu_name, $indent, &$options, $exclude,
 function menu_block_view_system_menu_block_alter(array &$build, BlockPluginInterface $block) {
   // Add contextual links for system menu blocks.
   $menus = menu_list_system_menus();
-  // @todo Clean up when http://drupal.org/node/1874498 lands.
-  list(, $menu_name) = explode(':', $block->getPluginId());
+  $menu_name = $block->getDerivativeId();
   if (isset($menus[$menu_name]) && isset($build['content'])) {
     foreach (element_children($build['content']) as $key) {
       $build['content']['#contextual_links']['menu'] = array('admin/structure/menu/manage', array($build['content'][$key]['#original_link']['menu_name']));
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 92f137b..b528f05 100644
--- a/core/modules/system/lib/Drupal/system/Plugin/Block/SystemMenuBlock.php
+++ b/core/modules/system/lib/Drupal/system/Plugin/Block/SystemMenuBlock.php
@@ -27,8 +27,7 @@ class SystemMenuBlock extends BlockBase {
    * Overrides \Drupal\block\BlockBase::access().
    */
   public function access() {
-    // @todo Clean up when http://drupal.org/node/1874498 lands.
-    list( , $derivative) = explode(':', $this->getPluginId());
+    $derivative = $this->getDerivativeId();
     return ($GLOBALS['user']->isAuthenticated() || in_array($derivative, array('main', 'tools', 'footer')));
   }
 
@@ -36,8 +35,7 @@ public function access() {
    * {@inheritdoc}
    */
   public function build() {
-    // @todo Clean up when http://drupal.org/node/1874498 lands.
-    list(, $menu) = explode(':', $this->getPluginId());
+    $menu = $this->getDerivativeId();
     return menu_tree($menu);
   }
 
diff --git a/core/modules/system/system.module b/core/modules/system/system.module
index cdfddea..6410a66 100644
--- a/core/modules/system/system.module
+++ b/core/modules/system/system.module
@@ -2301,10 +2301,7 @@ function system_user_timezone(&$form, &$form_state) {
  * Implements hook_preprocess_HOOK() for block templates.
  */
 function system_preprocess_block(&$variables) {
-  // Derive the base plugin ID.
-  // @todo Clean up when http://drupal.org/node/1874498 lands.
-  list($plugin_id, $derivative) = explode(':', $variables['plugin_id'] . ':');
-  switch ($plugin_id) {
+  switch ($variables['base_plugin_id']) {
     case 'system_powered_by_block':
       $variables['attributes']['role'] = 'complementary';
       break;
@@ -2315,7 +2312,7 @@ function system_preprocess_block(&$variables) {
 
     case 'system_menu_block':
       $menus = menu_list_system_menus();
-      if (isset($menus[$derivative])) {
+      if (isset($menus[$variables['derivative_plugin_id']])) {
         $variables['attributes']['role'] = 'navigation';
         $variables['attributes']['class'][] = 'block-menu';
       }
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);
diff --git a/core/tests/Drupal/Tests/Component/Plugin/PluginBaseTest.php b/core/tests/Drupal/Tests/Component/Plugin/PluginBaseTest.php
new file mode 100644
index 0000000..0bd247b
--- /dev/null
+++ b/core/tests/Drupal/Tests/Component/Plugin/PluginBaseTest.php
@@ -0,0 +1,115 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Tests\Component\Plugin\PluginBaseTest.
+ */
+
+namespace Drupal\Tests\Component\Plugin;
+
+use Drupal\Component\PhpStorage\PhpStorageFactory;
+use Drupal\Tests\UnitTestCase;
+
+/**
+ * Tests the plugin base.
+ *
+ * @group Drupal
+ *
+ * @see \Drupal\Component\Plugin\PluginBase
+ */
+class PluginBaseTest extends UnitTestCase {
+
+  public static function getInfo() {
+    return array(
+      'name' => 'Plugin base test',
+      'description' => 'Tests the plugin base',
+      'group' => 'Plugin',
+    );
+  }
+
+  /**
+   * Tests the getPluginId method.
+   *
+   * @see \Drupal\Component\Plugin\PluginBase::getPluginId()
+   */
+  public function testGetPluginId() {
+    $plugin_base = $this->getMockForAbstractClass('Drupal\Component\Plugin\PluginBase', array(
+      array(),
+      'base_id',
+      array()
+    ));
+
+    $this->assertEquals('base_id', $plugin_base->getPluginId());
+
+    $plugin_base = $this->getMockForAbstractClass('Drupal\Component\Plugin\PluginBase', array(
+      array(),
+      'base_id:derivative',
+      array()
+    ));
+
+    $this->assertEquals('base_id:derivative', $plugin_base->getPluginId());
+  }
+
+  /**
+   * Tests the getBasePluginId method.
+   *
+   * @see \Drupal\Component\Plugin\PluginBase::getBasePluginId()
+   */
+  public function testGetBasePluginId() {
+    $plugin_base = $this->getMockForAbstractClass('Drupal\Component\Plugin\PluginBase', array(
+      array(),
+      'base_id',
+      array()
+    ));
+
+    $this->assertEquals('base_id', $plugin_base->getBasePluginId());
+
+    $plugin_base = $this->getMockForAbstractClass('Drupal\Component\Plugin\PluginBase', array(
+      array(),
+      'base_id:derivative',
+      array()
+    ));
+
+    $this->assertEquals('base_id', $plugin_base->getBasePluginId());
+  }
+
+
+  /**
+   * Tests the getBasePluginId method.
+   *
+   * @see \Drupal\Component\Plugin\PluginBase::getBasePluginId()
+   */
+  public function testGetDerivativeId() {
+    $plugin_base = $this->getMockForAbstractClass('Drupal\Component\Plugin\PluginBase', array(
+      array(),
+      'base_id',
+      array()
+    ));
+
+    $this->assertEquals(NULL, $plugin_base->getDerivativeId());
+
+    $plugin_base = $this->getMockForAbstractClass('Drupal\Component\Plugin\PluginBase', array(
+      array(),
+      'base_id:derivative',
+      array()
+    ));
+
+    $this->assertEquals('derivative', $plugin_base->getDerivativeId());
+  }
+
+  /**
+   * Tests the getPluginDefinition method.
+   *
+   * @see \Drupal\Component\Plugin\PluginBase::getPluginDefinition()
+   */
+  public function testGetPluginDefinition() {
+    $plugin_base = $this->getMockForAbstractClass('Drupal\Component\Plugin\PluginBase', array(
+      array(),
+      'plugin_id',
+      array('value', array('key' => 'value'))
+    ));
+
+    $this->assertEquals(array('value', array('key' => 'value')), $plugin_base->getPluginDefinition());
+  }
+
+}
