diff --git a/core/lib/Drupal/Component/Plugin/Discovery/DerivativeDiscoveryDecorator.php b/core/lib/Drupal/Component/Plugin/Discovery/DerivativeDiscoveryDecorator.php
index 16281dfa898928ea9c0b5932f432de18cbd0db3c..027c59ad52489ecddbaffe7b61726e4b93f2a9a6 100644
--- a/core/lib/Drupal/Component/Plugin/Discovery/DerivativeDiscoveryDecorator.php
+++ b/core/lib/Drupal/Component/Plugin/Discovery/DerivativeDiscoveryDecorator.php
@@ -40,13 +40,21 @@ public function __construct(DiscoveryInterface $decorated) {
    *   not implement \Drupal\Component\Plugin\Derivative\DerivativeInterface.
    */
   public function getDefinition($plugin_id) {
+    $plugin_definition = $this->decorated->getDefinition($plugin_id);
     list($base_plugin_id, $derivative_id) = $this->decodePluginId($plugin_id);
-
-    $plugin_definition = $this->decorated->getDefinition($base_plugin_id);
-    if (isset($plugin_definition)) {
-      $derivative_fetcher = $this->getDerivativeFetcher($base_plugin_id, $plugin_definition);
+    $base_plugin_definition = $this->decorated->getDefinition($base_plugin_id);
+    if ($base_plugin_definition) {
+      $derivative_fetcher = $this->getDerivativeFetcher($base_plugin_id, $base_plugin_definition);
       if ($derivative_fetcher) {
-        $plugin_definition = $derivative_fetcher->getDerivativeDefinition($derivative_id, $plugin_definition);
+        $derivative_plugin_definition = $derivative_fetcher->getDerivativeDefinition($derivative_id, $base_plugin_definition);
+        // If a plugin defined itself as a derivative, merge in possible
+        // defaults from the derivative.
+        if ($derivative_id && isset($plugin_definition)) {
+          $plugin_definition += $derivative_plugin_definition ?: array();
+        }
+        else {
+          $plugin_definition = $derivative_plugin_definition;
+        }
       }
     }
 
@@ -79,10 +87,17 @@ protected function getDerivatives(array $base_plugin_definitions) {
         $derivative_definitions = $derivative_fetcher->getDerivativeDefinitions($plugin_definition);
         foreach ($derivative_definitions as $derivative_id => $derivative_definition) {
           $plugin_id = $this->encodePluginId($base_plugin_id, $derivative_id);
+          // Use this definition as defaults if a plugin already defined
+          // itself as this derivative.
+          if ($derivative_id && isset($base_plugin_definitions[$plugin_id])) {
+            $derivative_definition = $base_plugin_definitions[$plugin_id] + ($derivative_definition ?: array());
+          }
           $plugin_definitions[$plugin_id] = $derivative_definition;
         }
       }
-      else {
+      // If a plugin already defined itself as a derivative it might already
+      // be merged into the definitions.
+      elseif (!isset($plugin_definitions[$base_plugin_id])) {
         $plugin_definitions[$base_plugin_id] = $plugin_definition;
       }
     }
diff --git a/core/modules/comment/comment.views.inc b/core/modules/comment/comment.views.inc
index 63b9b48c5e02cc3c86a87bea1b51303a4ae55882..ac80d13e0921118b9fc5ebd4812d117be2a04178 100644
--- a/core/modules/comment/comment.views.inc
+++ b/core/modules/comment/comment.views.inc
@@ -676,15 +676,3 @@ function comment_views_data_alter(&$data) {
     }
   }
 }
-
-/**
- * Implements hook_views_plugins_row_alter().
- *
- * Replaces the generic row plugin by a custom one for comments.
- *
- * @see \Drupal\views\Plugin\views\row\EntityRow
- */
-function comment_views_plugins_row_alter(array &$plugins) {
-  $plugins['entity:comment']['class'] = 'Drupal\comment\Plugin\views\row\CommentRow';
-  $plugins['entity:comment']['provider'] = 'comment';
-}
diff --git a/core/modules/comment/lib/Drupal/comment/Plugin/views/row/CommentRow.php b/core/modules/comment/lib/Drupal/comment/Plugin/views/row/CommentRow.php
index 6da816115f12ea29ce06140052cbf970ea5f1520..6caa5233e61b872b23614ce5b7efd5c95faf4613 100644
--- a/core/modules/comment/lib/Drupal/comment/Plugin/views/row/CommentRow.php
+++ b/core/modules/comment/lib/Drupal/comment/Plugin/views/row/CommentRow.php
@@ -11,6 +11,10 @@
 
 /**
  * Plugin which performs a comment_view on the resulting object.
+ *
+ * @ViewsRow(
+ *   id = "entity:comment",
+ * )
  */
 class CommentRow extends EntityRow {
 
diff --git a/core/modules/node/lib/Drupal/node/Plugin/views/row/NodeRow.php b/core/modules/node/lib/Drupal/node/Plugin/views/row/NodeRow.php
index 01ea81b7381eb62f9269e06ce0fb1917cce28c20..de71343e2261c02ee992940224a62fd1abf9cc66 100644
--- a/core/modules/node/lib/Drupal/node/Plugin/views/row/NodeRow.php
+++ b/core/modules/node/lib/Drupal/node/Plugin/views/row/NodeRow.php
@@ -15,6 +15,10 @@
  * Most of the code on this object is in the theme function.
  *
  * @ingroup views_row_plugins
+ *
+ * @ViewsRow(
+ *   id = "entity:node",
+ * )
  */
 class NodeRow extends EntityRow {
 
diff --git a/core/modules/node/node.views.inc b/core/modules/node/node.views.inc
index e990571aab474a86ff979214757142e4eeb55e8b..136628faa8d746ad672aa959a7fc6d544940445a 100644
--- a/core/modules/node/node.views.inc
+++ b/core/modules/node/node.views.inc
@@ -656,15 +656,3 @@ function node_views_wizard() {
   }
 
 }
-
-/**
- * Implements hook_views_plugins_row_alter().
- *
- * Replaces the generic row plugin by a custom one for nodes.
- *
- * @see \Drupal\views\Plugin\views\row\EntityRow
- */
-function node_views_plugins_row_alter(array &$plugins) {
-  $plugins['entity:node']['class'] = 'Drupal\node\Plugin\views\row\NodeRow';
-  $plugins['entity:node']['provider'] = 'node';
-}
diff --git a/core/modules/system/lib/Drupal/system/Tests/Plugin/PluginTestBase.php b/core/modules/system/lib/Drupal/system/Tests/Plugin/PluginTestBase.php
index 917e4e724387df12ac4317dd7884638142e52de6..667d95464bc3c7081b804efb79280523b852846f 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Plugin/PluginTestBase.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Plugin/PluginTestBase.php
@@ -62,6 +62,11 @@ public function setUp() {
         'label' => 'Navigation',
         'class' => 'Drupal\plugin_test\Plugin\plugin_test\mock_block\MockMenuBlock',
       ),
+      'menu:foo' => array(
+        'label' => 'Base label',
+        'class' => 'Drupal\plugin_test\Plugin\plugin_test\mock_block\MockMenuBlock',
+        'setting' => 'default',
+      ),
       'layout' => array(
         'label' => 'Layout',
         'class' => 'Drupal\plugin_test\Plugin\plugin_test\mock_block\MockLayoutBlock',
diff --git a/core/modules/system/tests/modules/plugin_test/lib/Drupal/plugin_test/Plugin/MockBlockManager.php b/core/modules/system/tests/modules/plugin_test/lib/Drupal/plugin_test/Plugin/MockBlockManager.php
index 386841bc9a15afceb0aebb3e9946b45da326a227..cd3d0306ae211ca03f5bd9d7f786c080627e47f5 100644
--- a/core/modules/system/tests/modules/plugin_test/lib/Drupal/plugin_test/Plugin/MockBlockManager.php
+++ b/core/modules/system/tests/modules/plugin_test/lib/Drupal/plugin_test/Plugin/MockBlockManager.php
@@ -53,6 +53,11 @@ public function __construct() {
       'class' => 'Drupal\plugin_test\Plugin\plugin_test\mock_block\MockMenuBlock',
       'derivative' => 'Drupal\plugin_test\Plugin\plugin_test\mock_block\MockMenuBlockDeriver',
     ));
+    // A plugin defining itself as a derivative.
+    $this->discovery->setDefinition('menu:foo', array(
+      'label' => t('Base label'),
+      'class' => 'Drupal\plugin_test\Plugin\plugin_test\mock_block\MockMenuBlock',
+    ));
 
     // A block plugin that can optionally be derived: the layout block plugin.
     // A layout is a special kind of block into which other blocks can be
diff --git a/core/modules/system/tests/modules/plugin_test/lib/Drupal/plugin_test/Plugin/plugin_test/mock_block/MockMenuBlockDeriver.php b/core/modules/system/tests/modules/plugin_test/lib/Drupal/plugin_test/Plugin/plugin_test/mock_block/MockMenuBlockDeriver.php
index 6f1025173565f70f06eacd475fba0acc3b97abcc..35e7bca170dacd0e29b834c38173750af27e4075 100644
--- a/core/modules/system/tests/modules/plugin_test/lib/Drupal/plugin_test/Plugin/plugin_test/mock_block/MockMenuBlockDeriver.php
+++ b/core/modules/system/tests/modules/plugin_test/lib/Drupal/plugin_test/Plugin/plugin_test/mock_block/MockMenuBlockDeriver.php
@@ -46,6 +46,12 @@ public function getDerivativeDefinitions(array $base_plugin_definition) {
       'navigation' => array(
         'label' => t('Navigation'),
       ) + $base_plugin_definition,
+      'foo' => array(
+        // Instead of the derivative label, the specific label will be used.
+        'label' => t('Derivative label'),
+        // This setting will be merged in.
+         'setting' => 'default'
+      ) + $base_plugin_definition,
     );
 
     return $derivatives;
diff --git a/core/modules/user/lib/Drupal/user/Plugin/views/row/UserRow.php b/core/modules/user/lib/Drupal/user/Plugin/views/row/UserRow.php
index 19e1946c77cafba57ff5bb0a96c743cf890a43a1..c8db4061e3e26153f9e7921327c8d4e532b5821a 100644
--- a/core/modules/user/lib/Drupal/user/Plugin/views/row/UserRow.php
+++ b/core/modules/user/lib/Drupal/user/Plugin/views/row/UserRow.php
@@ -13,6 +13,10 @@
  * A row plugin which renders a user.
  *
  * @ingroup views_row_plugins
+ *
+ * @ViewsRow(
+ *   id = "entity:user",
+ * )
  */
 class UserRow extends EntityRow {
 
diff --git a/core/modules/user/user.views.inc b/core/modules/user/user.views.inc
index d3ddf924612726289ef6063ae45f7b33fe00b016..093863e8e49766be853a1cca05341be391bdea59 100644
--- a/core/modules/user/user.views.inc
+++ b/core/modules/user/user.views.inc
@@ -378,16 +378,3 @@ function user_views_data_alter(&$data) {
     ),
   );
 }
-
-
-/**
- * Implements hook_views_plugins_row_alter().
- *
- * Replaces the generic row plugin by a custom one for users.
- *
- * @see \Drupal\views\Plugin\views\row\EntityRow
- */
-function user_views_plugins_row_alter(array &$plugins) {
-  $plugins['entity:user']['class'] = 'Drupal\user\Plugin\views\row\UserRow';
-  $plugins['entity:user']['provider'] = 'user';
-}