diff --git a/core/lib/Drupal/Core/Action/ActionManager.php b/core/lib/Drupal/Core/Action/ActionManager.php
index d3a4c0a..2b4002d 100644
--- a/core/lib/Drupal/Core/Action/ActionManager.php
+++ b/core/lib/Drupal/Core/Action/ActionManager.php
@@ -22,6 +22,11 @@
 class ActionManager extends DefaultPluginManager {
 
   /**
+   * {@inheritdoc}
+   */
+  protected $interface = '\Drupal\Core\Action\ActionInterface';
+
+  /**
    * Constructs a new class instance.
    *
    * @param \Traversable $namespaces
diff --git a/core/lib/Drupal/Core/Archiver/ArchiverManager.php b/core/lib/Drupal/Core/Archiver/ArchiverManager.php
index b161bd9..ac11937 100644
--- a/core/lib/Drupal/Core/Archiver/ArchiverManager.php
+++ b/core/lib/Drupal/Core/Archiver/ArchiverManager.php
@@ -1,6 +1,7 @@
 <?php
 
 /**
+ * @file
  * Contains \Drupal\Core\Archiver\ArchiverManager.
  */
 
@@ -21,6 +22,11 @@
 class ArchiverManager extends DefaultPluginManager {
 
   /**
+   * {@inheritdoc}
+   */
+  protected $interface = '\Drupal\Core\Archiver\ArchiverInterface';
+
+  /**
    * Constructs a ArchiverManager object.
    *
    * @param \Traversable $namespaces
diff --git a/core/lib/Drupal/Core/Condition/ConditionManager.php b/core/lib/Drupal/Core/Condition/ConditionManager.php
index db0fa43..d7f717e 100644
--- a/core/lib/Drupal/Core/Condition/ConditionManager.php
+++ b/core/lib/Drupal/Core/Condition/ConditionManager.php
@@ -28,6 +28,11 @@ class ConditionManager extends DefaultPluginManager implements ExecutableManager
   use ContextAwarePluginManagerTrait;
 
   /**
+   * {@inheritdoc}
+   */
+  protected $interface = '\Drupal\Core\Condition\ConditionInterface';
+
+  /**
    * Constructs a ConditionManager object.
    *
    * @param \Traversable $namespaces
diff --git a/core/lib/Drupal/Core/Display/VariantManager.php b/core/lib/Drupal/Core/Display/VariantManager.php
index 7f18a29..384c484 100755
--- a/core/lib/Drupal/Core/Display/VariantManager.php
+++ b/core/lib/Drupal/Core/Display/VariantManager.php
@@ -20,6 +20,11 @@
 class VariantManager extends DefaultPluginManager {
 
   /**
+   * {@inheritdoc}
+   */
+  protected $interface = '\Drupal\Core\Display\VariantInterface';
+
+  /**
    * Constructs a new VariantManager.
    *
    * @param \Traversable $namespaces
diff --git a/core/lib/Drupal/Core/Entity/EntityManager.php b/core/lib/Drupal/Core/Entity/EntityManager.php
index 2f16516..4c0ad20 100644
--- a/core/lib/Drupal/Core/Entity/EntityManager.php
+++ b/core/lib/Drupal/Core/Entity/EntityManager.php
@@ -47,6 +47,11 @@ class EntityManager extends DefaultPluginManager implements EntityManagerInterfa
   use StringTranslationTrait;
 
   /**
+   * {@inheritdoc}
+   */
+  protected $interface = '\Drupal\Core\Entity\EntityInterface';
+
+  /**
    * Extra fields by bundle.
    *
    * @var array
diff --git a/core/lib/Drupal/Core/Field/FieldTypePluginManager.php b/core/lib/Drupal/Core/Field/FieldTypePluginManager.php
index 6a5f39a..3a7febd 100644
--- a/core/lib/Drupal/Core/Field/FieldTypePluginManager.php
+++ b/core/lib/Drupal/Core/Field/FieldTypePluginManager.php
@@ -20,6 +20,11 @@
 class FieldTypePluginManager extends DefaultPluginManager implements FieldTypePluginManagerInterface {
 
   /**
+   * {@inheritdoc}
+   */
+  protected $interface = '\Drupal\Core\Field\FieldItemInterface';
+
+  /**
    * Constructs the FieldTypePluginManager object
    *
    * @param \Traversable $namespaces
diff --git a/core/lib/Drupal/Core/Field/FormatterPluginManager.php b/core/lib/Drupal/Core/Field/FormatterPluginManager.php
index 5d5cea2..fc658ff 100644
--- a/core/lib/Drupal/Core/Field/FormatterPluginManager.php
+++ b/core/lib/Drupal/Core/Field/FormatterPluginManager.php
@@ -20,6 +20,11 @@
 class FormatterPluginManager extends DefaultPluginManager {
 
   /**
+   * {@inheritdoc}
+   */
+  protected $interface = '\Drupal\Core\Field\FormatterInterface';
+
+  /**
    * An array of formatter options for each field type.
    *
    * @var array
diff --git a/core/lib/Drupal/Core/Field/WidgetPluginManager.php b/core/lib/Drupal/Core/Field/WidgetPluginManager.php
index 207b5e3..8d525b1 100644
--- a/core/lib/Drupal/Core/Field/WidgetPluginManager.php
+++ b/core/lib/Drupal/Core/Field/WidgetPluginManager.php
@@ -20,6 +20,11 @@
 class WidgetPluginManager extends DefaultPluginManager {
 
   /**
+   * {@inheritdoc}
+   */
+  protected $interface = '\Drupal\Core\Field\WidgetInterface';
+
+  /**
    * The field type manager to define field.
    *
    * @var \Drupal\Core\Field\FieldTypePluginManagerInterface
diff --git a/core/lib/Drupal/Core/ImageToolkit/ImageToolkitManager.php b/core/lib/Drupal/Core/ImageToolkit/ImageToolkitManager.php
index 270f870..5b04da4 100644
--- a/core/lib/Drupal/Core/ImageToolkit/ImageToolkitManager.php
+++ b/core/lib/Drupal/Core/ImageToolkit/ImageToolkitManager.php
@@ -20,6 +20,11 @@
 class ImageToolkitManager extends DefaultPluginManager {
 
   /**
+   * {@inheritdoc}
+   */
+  protected $interface = '\Drupal\Core\ImageToolkit\ImageToolkitInterface';
+
+  /**
    * The config factory.
    *
    * @var \Drupal\Core\Config\ConfigFactoryInterface
diff --git a/core/lib/Drupal/Core/ImageToolkit/ImageToolkitOperationManager.php b/core/lib/Drupal/Core/ImageToolkit/ImageToolkitOperationManager.php
index 20ecc55..8e106f9 100644
--- a/core/lib/Drupal/Core/ImageToolkit/ImageToolkitOperationManager.php
+++ b/core/lib/Drupal/Core/ImageToolkit/ImageToolkitOperationManager.php
@@ -21,6 +21,11 @@
 class ImageToolkitOperationManager extends DefaultPluginManager implements ImageToolkitOperationManagerInterface {
 
   /**
+   * {@inheritdoc}
+   */
+  protected $interface = '\Drupal\Core\ImageToolkit\ImageToolkitOperationInterface';
+
+  /**
    * A logger instance.
    *
    * @var \Psr\Log\LoggerInterface
diff --git a/core/lib/Drupal/Core/Mail/MailManager.php b/core/lib/Drupal/Core/Mail/MailManager.php
index 48e53cf..13a1c7d 100644
--- a/core/lib/Drupal/Core/Mail/MailManager.php
+++ b/core/lib/Drupal/Core/Mail/MailManager.php
@@ -29,6 +29,11 @@ class MailManager extends DefaultPluginManager implements MailManagerInterface {
   use StringTranslationTrait;
 
   /**
+   * {@inheritdoc}
+   */
+  protected $interface = '\Drupal\Core\Mail\MailInterface';
+
+  /**
    * The config factory.
    *
    * @var \Drupal\Core\Config\ConfigFactoryInterface
diff --git a/core/lib/Drupal/Core/Menu/ContextualLinkManager.php b/core/lib/Drupal/Core/Menu/ContextualLinkManager.php
index cbbf4e4..b4bd175 100644
--- a/core/lib/Drupal/Core/Menu/ContextualLinkManager.php
+++ b/core/lib/Drupal/Core/Menu/ContextualLinkManager.php
@@ -28,6 +28,11 @@
 class ContextualLinkManager extends DefaultPluginManager implements ContextualLinkManagerInterface {
 
   /**
+   * {@inheritdoc}
+   */
+  protected $interface = '\Drupal\Core\Menu\ContextualLinkInterface';
+
+  /**
    * Provides default values for a contextual link definition.
    *
    * @var array
diff --git a/core/lib/Drupal/Core/Menu/LocalActionManager.php b/core/lib/Drupal/Core/Menu/LocalActionManager.php
index 1167357..e881aa5 100644
--- a/core/lib/Drupal/Core/Menu/LocalActionManager.php
+++ b/core/lib/Drupal/Core/Menu/LocalActionManager.php
@@ -31,6 +31,11 @@
 class LocalActionManager extends DefaultPluginManager {
 
   /**
+   * {@inheritdoc}
+   */
+  protected $interface = '\Drupal\Core\Menu\LocalActionInterface';
+
+  /**
    * Provides some default values for all local action plugins.
    *
    * @var array
diff --git a/core/lib/Drupal/Core/Menu/LocalTaskManager.php b/core/lib/Drupal/Core/Menu/LocalTaskManager.php
index 839ef32..ef0a652 100644
--- a/core/lib/Drupal/Core/Menu/LocalTaskManager.php
+++ b/core/lib/Drupal/Core/Menu/LocalTaskManager.php
@@ -35,6 +35,11 @@ class LocalTaskManager extends DefaultPluginManager {
   /**
    * {@inheritdoc}
    */
+  protected $interface = '\Drupal\Core\Menu\LocalTaskInterface';
+
+  /**
+   * {@inheritdoc}
+   */
   protected $defaults = array(
     // (required) The name of the route this task links to.
     'route_name' => '',
diff --git a/core/lib/Drupal/Core/Plugin/DefaultPluginManager.php b/core/lib/Drupal/Core/Plugin/DefaultPluginManager.php
index e1d0731..7fb48fa 100644
--- a/core/lib/Drupal/Core/Plugin/DefaultPluginManager.php
+++ b/core/lib/Drupal/Core/Plugin/DefaultPluginManager.php
@@ -9,7 +9,9 @@
 
 use Drupal\Component\Plugin\Discovery\CachedDiscoveryInterface;
 use Drupal\Component\Plugin\Discovery\DiscoveryCachedTrait;
+use Drupal\Component\Plugin\Exception\PluginException;
 use Drupal\Component\Plugin\Exception\PluginNotFoundException;
+use Drupal\Component\Utility\String;
 use Drupal\Core\Plugin\Discovery\ContainerDerivativeDiscoveryDecorator;
 use Drupal\Component\Plugin\PluginManagerBase;
 use Drupal\Component\Plugin\PluginManagerInterface;
@@ -83,6 +85,13 @@ class DefaultPluginManager extends PluginManagerBase implements PluginManagerInt
   protected $defaults = array();
 
   /**
+   * Defines an interface each plugin should implement.
+   *
+   * @var string
+   */
+  protected $interface;
+
+  /**
    * Creates the discovery object.
    *
    * @param string|bool $subdir
@@ -237,8 +246,32 @@ protected function findDefinitions() {
       if (isset($plugin_definition['provider']) && !in_array($plugin_definition['provider'], array('core', 'component')) && !$this->moduleHandler->moduleExists($plugin_definition['provider'])) {
         unset($definitions[$plugin_id]);
       }
+      $this->enforcePluginInterface($plugin_id, $plugin_definition);
     }
     return $definitions;
   }
 
+  /**
+   * Enforces that a plugin implements the required interface.
+   *
+   * @param string $plugin_id
+   * @param array $plugin_definition
+   *
+   * @throws \Drupal\Component\Plugin\Exception\PluginException
+   */
+  protected function enforcePluginInterface($plugin_id, $plugin_definition) {
+    // If there are multiple valid interfaces, check for at least one.
+    if (is_array($this->interface) && array_intersect(class_implements($plugin_definition['class']), $this->interface)) {
+      return;
+    }
+    elseif (is_string($this->interface) && is_subclass_of($plugin_definition['class'], $this->interface)) {
+      return;
+    }
+    throw new PluginException(String::format('Plugin @plugin_id in @provider should implement interface @interface', array(
+      '@plugin_id' => $plugin_id,
+      '@provider' => $plugin_definition['provider'],
+      '@interface' => is_array($this->interface) ? implode(', ', $this->interface) : $this->interface,
+    )));
+  }
+
 }
diff --git a/core/lib/Drupal/Core/Render/ElementInfoManager.php b/core/lib/Drupal/Core/Render/ElementInfoManager.php
index 1dd2be4..a0264d2 100644
--- a/core/lib/Drupal/Core/Render/ElementInfoManager.php
+++ b/core/lib/Drupal/Core/Render/ElementInfoManager.php
@@ -26,6 +26,11 @@
 class ElementInfoManager extends DefaultPluginManager implements ElementInfoManagerInterface {
 
   /**
+   * {@inheritdoc}
+   */
+  protected $interface = '\Drupal\Core\Render\Element\ElementInterface';
+
+  /**
    * Stores the available element information.
    *
    * @var array
diff --git a/core/lib/Drupal/Core/TypedData/TypedDataManager.php b/core/lib/Drupal/Core/TypedData/TypedDataManager.php
index c9afe86..7889be1 100644
--- a/core/lib/Drupal/Core/TypedData/TypedDataManager.php
+++ b/core/lib/Drupal/Core/TypedData/TypedDataManager.php
@@ -395,4 +395,11 @@ public function clearCachedDefinitions() {
     $this->prototypes = array();
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  protected function enforcePluginInterface($plugin_id, $plugin_definition) {
+    // Do not enforce an interface for typed data plugins.
+  }
+
 }
diff --git a/core/lib/Drupal/Core/Validation/ConstraintManager.php b/core/lib/Drupal/Core/Validation/ConstraintManager.php
index a2b46d3..70adb95 100644
--- a/core/lib/Drupal/Core/Validation/ConstraintManager.php
+++ b/core/lib/Drupal/Core/Validation/ConstraintManager.php
@@ -138,4 +138,12 @@ public function getDefinitionsByType($type) {
     }
     return $definitions;
   }
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function enforcePluginInterface($plugin_id, $plugin_definition) {
+    // Do not enforce an interface for constraint plugins.
+  }
+
 }
diff --git a/core/modules/aggregator/src/Plugin/AggregatorPluginManager.php b/core/modules/aggregator/src/Plugin/AggregatorPluginManager.php
index 53c3acd..619e125 100644
--- a/core/modules/aggregator/src/Plugin/AggregatorPluginManager.php
+++ b/core/modules/aggregator/src/Plugin/AggregatorPluginManager.php
@@ -7,6 +7,8 @@
 
 namespace Drupal\aggregator\Plugin;
 
+use Drupal\Component\Plugin\Exception\PluginException;
+use Drupal\Component\Utility\String;
 use Drupal\Core\Cache\CacheBackendInterface;
 use Drupal\Core\Extension\ModuleHandlerInterface;
 use Drupal\Core\Plugin\DefaultPluginManager;
@@ -26,6 +28,15 @@
 class AggregatorPluginManager extends DefaultPluginManager {
 
   /**
+   * {@inheritdoc}
+   */
+  protected $interface = array(
+    'Drupal\aggregator\Plugin\FetcherInterface',
+    'Drupal\aggregator\Plugin\ParserInterface',
+    'Drupal\aggregator\Plugin\ProcessorInterface',
+  );
+
+  /**
    * Constructs a AggregatorPluginManager object.
    *
    * @param string $type
diff --git a/core/modules/block/src/BlockManager.php b/core/modules/block/src/BlockManager.php
index 706af51..d86cfe9 100644
--- a/core/modules/block/src/BlockManager.php
+++ b/core/modules/block/src/BlockManager.php
@@ -27,6 +27,11 @@ class BlockManager extends DefaultPluginManager implements BlockManagerInterface
   use ContextAwarePluginManagerTrait;
 
   /**
+   * {@inheritdoc}
+   */
+  protected $interface = '\Drupal\block\BlockPluginInterface';
+
+  /**
    * An array of all available modules and their data.
    *
    * @var array
diff --git a/core/modules/ckeditor/src/CKEditorPluginManager.php b/core/modules/ckeditor/src/CKEditorPluginManager.php
index 289c906..c79c580 100644
--- a/core/modules/ckeditor/src/CKEditorPluginManager.php
+++ b/core/modules/ckeditor/src/CKEditorPluginManager.php
@@ -28,6 +28,11 @@
 class CKEditorPluginManager extends DefaultPluginManager {
 
   /**
+   * {@inheritdoc}
+   */
+  protected $interface = '\Drupal\ckeditor\CKEditorPluginInterface';
+
+  /**
    * Constructs a CKEditorPluginManager object.
    *
    * @param \Traversable $namespaces
diff --git a/core/modules/config_translation/src/ConfigMapperManager.php b/core/modules/config_translation/src/ConfigMapperManager.php
index 8eb3735..9dee11a 100644
--- a/core/modules/config_translation/src/ConfigMapperManager.php
+++ b/core/modules/config_translation/src/ConfigMapperManager.php
@@ -29,6 +29,11 @@
 class ConfigMapperManager extends DefaultPluginManager implements ConfigMapperManagerInterface {
 
   /**
+   * {@inheritdoc}
+   */
+  protected $interface = '\Drupal\config_translation\ConfigMapperInterface';
+
+  /**
    * The typed config manager.
    *
    * @var \Drupal\Core\Config\TypedConfigManagerInterface
diff --git a/core/modules/editor/src/Plugin/EditorManager.php b/core/modules/editor/src/Plugin/EditorManager.php
index 1dd6df2..332e4dc 100644
--- a/core/modules/editor/src/Plugin/EditorManager.php
+++ b/core/modules/editor/src/Plugin/EditorManager.php
@@ -22,6 +22,11 @@
 class EditorManager extends DefaultPluginManager {
 
   /**
+   * {@inheritdoc}
+   */
+  protected $interface = '\Drupal\editor\Plugin\EditorPluginInterface';
+
+  /**
    * Constructs an EditorManager object.
    *
    * @param \Traversable $namespaces
diff --git a/core/modules/entity_reference/src/Plugin/Type/SelectionPluginManager.php b/core/modules/entity_reference/src/Plugin/Type/SelectionPluginManager.php
index ce5ff83..c40dde0 100644
--- a/core/modules/entity_reference/src/Plugin/Type/SelectionPluginManager.php
+++ b/core/modules/entity_reference/src/Plugin/Type/SelectionPluginManager.php
@@ -31,6 +31,11 @@ class SelectionPluginManager extends DefaultPluginManager {
   /**
    * {@inheritdoc}
    */
+  protected $interface = '\Drupal\entity_reference\Plugin\Type\Selection\SelectionInterface';
+
+  /**
+   * {@inheritdoc}
+   */
   public function __construct(\Traversable $namespaces, CacheBackendInterface $cache_backend, ModuleHandlerInterface $module_handler) {
     $this->discovery = new AnnotatedClassDiscovery('Plugin/entity_reference/selection', $namespaces, 'Drupal\entity_reference\Annotation\EntityReferenceSelection');
 
diff --git a/core/modules/filter/src/FilterPluginManager.php b/core/modules/filter/src/FilterPluginManager.php
index 77a3c71..650d99a 100644
--- a/core/modules/filter/src/FilterPluginManager.php
+++ b/core/modules/filter/src/FilterPluginManager.php
@@ -23,6 +23,11 @@
 class FilterPluginManager extends DefaultPluginManager {
 
   /**
+   * {@inheritdoc}
+   */
+  protected $interface = '\Drupal\filter\Plugin\FilterInterface';
+
+  /**
    * Constructs a FilterPluginManager object.
    *
    * @param \Traversable $namespaces
diff --git a/core/modules/image/src/ImageEffectManager.php b/core/modules/image/src/ImageEffectManager.php
index 4885450..3d5a6c0 100644
--- a/core/modules/image/src/ImageEffectManager.php
+++ b/core/modules/image/src/ImageEffectManager.php
@@ -17,6 +17,11 @@
 class ImageEffectManager extends DefaultPluginManager {
 
   /**
+   * {@inheritdoc}
+   */
+  protected $interface = '\Drupal\image\ImageEffectInterface';
+
+  /**
    * Constructs a new ImageEffectManager.
    *
    * @param \Traversable $namespaces
diff --git a/core/modules/language/src/LanguageNegotiationMethodManager.php b/core/modules/language/src/LanguageNegotiationMethodManager.php
index 681c67c..14201b7 100644
--- a/core/modules/language/src/LanguageNegotiationMethodManager.php
+++ b/core/modules/language/src/LanguageNegotiationMethodManager.php
@@ -17,6 +17,11 @@
 class LanguageNegotiationMethodManager extends DefaultPluginManager {
 
   /**
+   * {@inheritdoc}
+   */
+  protected $interface = '\Drupal\language\LanguageNegotiationMethodInterface';
+
+  /**
    * Constructs a new LanguageNegotiationMethodManager object.
    *
    * @param \Traversable $namespaces
diff --git a/core/modules/migrate/src/Plugin/MigrateEntityDestinationFieldInterface.php b/core/modules/migrate/src/Plugin/MigrateEntityDestinationFieldInterface.php
index 4cefa2f..7d2696f 100644
--- a/core/modules/migrate/src/Plugin/MigrateEntityDestinationFieldInterface.php
+++ b/core/modules/migrate/src/Plugin/MigrateEntityDestinationFieldInterface.php
@@ -6,12 +6,13 @@
 
 namespace Drupal\migrate\Plugin;
 
+use Drupal\Component\Plugin\PluginInspectionInterface;
 use Drupal\Core\Field\FieldDefinitionInterface;
 
 /**
  * Handle the importing of a specific configurable field type.
  */
-interface MigrateEntityDestinationFieldInterface {
+interface MigrateEntityDestinationFieldInterface extends PluginInspectionInterface {
 
   /**
    * Convert an array of values into an array structure fit for entity_create.
diff --git a/core/modules/migrate/src/Plugin/MigratePluginManager.php b/core/modules/migrate/src/Plugin/MigratePluginManager.php
index 0ae77be..7cfe943 100644
--- a/core/modules/migrate/src/Plugin/MigratePluginManager.php
+++ b/core/modules/migrate/src/Plugin/MigratePluginManager.php
@@ -2,7 +2,7 @@
 
 /**
  * @file
- * Contains \Drupal\migrate\MigraterPluginManager.
+ * Contains \Drupal\migrate\Plugin\MigratePluginManager.
  */
 
 namespace Drupal\migrate\Plugin;
@@ -30,6 +30,17 @@
 class MigratePluginManager extends DefaultPluginManager {
 
   /**
+   * {@inheritdoc}
+   */
+  protected $interface = array(
+    'Drupal\migrate\Plugin\MigrateDestinationInterface',
+    'Drupal\migrate\Plugin\MigrateProcessInterface',
+    'Drupal\migrate\Plugin\MigrateSourceInterface',
+    'Drupal\migrate\Plugin\MigrateIdMapInterface',
+    'Drupal\migrate\Plugin\MigrateEntityDestinationFieldInterface',
+  );
+
+  /**
    * Constructs a MigratePluginManager object.
    *
    * @param string $type
diff --git a/core/modules/migrate_drupal/migrate_drupal.services.yml b/core/modules/migrate_drupal/migrate_drupal.services.yml
index 6dd03c0..2c8f00c 100644
--- a/core/modules/migrate_drupal/migrate_drupal.services.yml
+++ b/core/modules/migrate_drupal/migrate_drupal.services.yml
@@ -1,4 +1,4 @@
 services:
   plugin.manager.migrate.load:
-    class: Drupal\migrate\Plugin\MigratePluginManager
+    class: Drupal\migrate_drupal\Plugin\MigratePluginManager
     arguments: [load, '@container.namespaces', '@cache.discovery', '@module_handler']
diff --git a/core/modules/migrate_drupal/src/Plugin/MigrateLoadInterface.php b/core/modules/migrate_drupal/src/Plugin/MigrateLoadInterface.php
index 34dd07b..f5545e8 100644
--- a/core/modules/migrate_drupal/src/Plugin/MigrateLoadInterface.php
+++ b/core/modules/migrate_drupal/src/Plugin/MigrateLoadInterface.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\migrate_drupal\Plugin;
 
+use Drupal\Component\Plugin\PluginInspectionInterface;
 use Drupal\Core\Entity\EntityStorageInterface;
 
 /**
@@ -16,7 +17,7 @@
  *
  * @ingroup migration
  */
-interface MigrateLoadInterface {
+interface MigrateLoadInterface extends PluginInspectionInterface {
 
   /**
    * Load an additional migration.
diff --git a/core/modules/migrate_drupal/src/Plugin/MigratePluginManager.php b/core/modules/migrate_drupal/src/Plugin/MigratePluginManager.php
new file mode 100644
index 0000000..1a1f881
--- /dev/null
+++ b/core/modules/migrate_drupal/src/Plugin/MigratePluginManager.php
@@ -0,0 +1,26 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\migrate\Plugin\MigratePluginManager.
+ */
+
+namespace Drupal\migrate_drupal\Plugin;
+
+use Drupal\migrate\Plugin\MigratePluginManager as BaseMigratePluginManager;
+
+/**
+ * Manages migrate_drupal plugins.
+ *
+ * @see plugin_api
+ *
+ * @ingroup migration
+ */
+class MigratePluginManager extends BaseMigratePluginManager {
+
+  /**
+   * {@inheritdoc}
+   */
+  protected $interface = 'Drupal\migrate_drupal\Plugin\MigrateLoadInterface';
+
+}
diff --git a/core/modules/quickedit/src/Plugin/InPlaceEditorManager.php b/core/modules/quickedit/src/Plugin/InPlaceEditorManager.php
index 876da2d..c6c937f 100644
--- a/core/modules/quickedit/src/Plugin/InPlaceEditorManager.php
+++ b/core/modules/quickedit/src/Plugin/InPlaceEditorManager.php
@@ -24,6 +24,11 @@
 class InPlaceEditorManager extends DefaultPluginManager {
 
   /**
+   * {@inheritdoc}
+   */
+  protected $interface = '\Drupal\quickedit\Plugin\InPlaceEditorInterface';
+
+  /**
    * Constructs a InPlaceEditorManager object.
    *
    * @param \Traversable $namespaces
diff --git a/core/modules/rest/src/Plugin/Type/ResourcePluginManager.php b/core/modules/rest/src/Plugin/Type/ResourcePluginManager.php
index ec9cb9f..4569df8 100644
--- a/core/modules/rest/src/Plugin/Type/ResourcePluginManager.php
+++ b/core/modules/rest/src/Plugin/Type/ResourcePluginManager.php
@@ -22,6 +22,11 @@
 class ResourcePluginManager extends DefaultPluginManager {
 
   /**
+   * {@inheritdoc}
+   */
+  protected $interface = '\Drupal\rest\Plugin\ResourceInterface';
+
+  /**
    * Constructs a new \Drupal\rest\Plugin\Type\ResourcePluginManager object.
    *
    * @param \Traversable $namespaces
diff --git a/core/modules/search/src/SearchPluginManager.php b/core/modules/search/src/SearchPluginManager.php
index 5670e71..c1cc34c 100644
--- a/core/modules/search/src/SearchPluginManager.php
+++ b/core/modules/search/src/SearchPluginManager.php
@@ -17,6 +17,11 @@
 class SearchPluginManager extends DefaultPluginManager {
 
   /**
+   * {@inheritdoc}
+   */
+  protected $interface = '\Drupal\search\Plugin\SearchInterface';
+
+  /**
    * Constructs SearchPluginManager
    *
    * @param \Traversable $namespaces
diff --git a/core/modules/system/tests/modules/plugin_test/src/Plugin/DefaultsTestPluginManager.php b/core/modules/system/tests/modules/plugin_test/src/Plugin/DefaultsTestPluginManager.php
index e81c39e..68026e1 100644
--- a/core/modules/system/tests/modules/plugin_test/src/Plugin/DefaultsTestPluginManager.php
+++ b/core/modules/system/tests/modules/plugin_test/src/Plugin/DefaultsTestPluginManager.php
@@ -17,6 +17,11 @@
  */
 class DefaultsTestPluginManager extends DefaultPluginManager {
 
+  /**
+   * {@inheritdoc}
+   */
+  protected $interface = '\Drupal\Component\Plugin\PluginInspectionInterface';
+
  /**
   * Constructs a new DefaultsTestPluginManager instance.
   *
diff --git a/core/modules/system/tests/modules/plugin_test/src/Plugin/plugin_test/fruit/Apple.php b/core/modules/system/tests/modules/plugin_test/src/Plugin/plugin_test/fruit/Apple.php
index 9aabeca..d81b6ba 100644
--- a/core/modules/system/tests/modules/plugin_test/src/Plugin/plugin_test/fruit/Apple.php
+++ b/core/modules/system/tests/modules/plugin_test/src/Plugin/plugin_test/fruit/Apple.php
@@ -14,4 +14,4 @@
  *   color = "green"
  * )
  */
-class Apple {}
+class Apple implements FruitInterface {}
diff --git a/core/modules/system/tests/modules/plugin_test/src/Plugin/plugin_test/fruit/Banana.php b/core/modules/system/tests/modules/plugin_test/src/Plugin/plugin_test/fruit/Banana.php
index 4801da5..5e4d180 100644
--- a/core/modules/system/tests/modules/plugin_test/src/Plugin/plugin_test/fruit/Banana.php
+++ b/core/modules/system/tests/modules/plugin_test/src/Plugin/plugin_test/fruit/Banana.php
@@ -17,6 +17,6 @@
  *   }
  * )
  */
-class Banana {
+class Banana implements FruitInterface {
 
 }
diff --git a/core/modules/system/tests/modules/plugin_test/src/Plugin/plugin_test/fruit/Cherry.php b/core/modules/system/tests/modules/plugin_test/src/Plugin/plugin_test/fruit/Cherry.php
index d22b90a..30db552 100644
--- a/core/modules/system/tests/modules/plugin_test/src/Plugin/plugin_test/fruit/Cherry.php
+++ b/core/modules/system/tests/modules/plugin_test/src/Plugin/plugin_test/fruit/Cherry.php
@@ -14,4 +14,4 @@
  *   color = "red"
  * )
  */
-class Cherry {}
+class Cherry implements FruitInterface {}
diff --git a/core/modules/system/tests/modules/plugin_test/src/Plugin/plugin_test/fruit/FruitInterface.php b/core/modules/system/tests/modules/plugin_test/src/Plugin/plugin_test/fruit/FruitInterface.php
new file mode 100644
index 0000000..4c26071
--- /dev/null
+++ b/core/modules/system/tests/modules/plugin_test/src/Plugin/plugin_test/fruit/FruitInterface.php
@@ -0,0 +1,14 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\plugin_test\Plugin\plugin_test\fruit\FruitInterface.
+ */
+
+namespace Drupal\plugin_test\Plugin\plugin_test\fruit;
+
+/**
+ * Provides an interface for test plugins.
+ */
+interface FruitInterface { }
+
diff --git a/core/modules/system/tests/modules/plugin_test/src/Plugin/plugin_test/fruit/Apple.php b/core/modules/system/tests/modules/plugin_test/src/Plugin/plugin_test/fruit/Kale.php
similarity index 50%
copy from core/modules/system/tests/modules/plugin_test/src/Plugin/plugin_test/fruit/Apple.php
copy to core/modules/system/tests/modules/plugin_test/src/Plugin/plugin_test/fruit/Kale.php
index 9aabeca..9c69b15 100644
--- a/core/modules/system/tests/modules/plugin_test/src/Plugin/plugin_test/fruit/Apple.php
+++ b/core/modules/system/tests/modules/plugin_test/src/Plugin/plugin_test/fruit/Kale.php
@@ -2,16 +2,16 @@
 
 /**
  * @file
- * Definition of Drupal\plugin_test\Plugin\plugin_test\fruit\Apple.
+ * Contains \Drupal\plugin_test\Plugin\plugin_test\fruit\Kale.
  */
 
 namespace Drupal\plugin_test\Plugin\plugin_test\fruit;
 
 /**
  * @Plugin(
- *   id = "apple",
- *   label = "Apple",
+ *   id = "kale",
+ *   label = "Kale",
  *   color = "green"
  * )
  */
-class Apple {}
+class Kale {}
diff --git a/core/modules/system/tests/modules/plugin_test/src/Plugin/plugin_test/fruit/Orange.php b/core/modules/system/tests/modules/plugin_test/src/Plugin/plugin_test/fruit/Orange.php
index 27d7d00..10ba4ea 100644
--- a/core/modules/system/tests/modules/plugin_test/src/Plugin/plugin_test/fruit/Orange.php
+++ b/core/modules/system/tests/modules/plugin_test/src/Plugin/plugin_test/fruit/Orange.php
@@ -14,4 +14,4 @@
  *   color = "orange"
  * )
  */
-class Orange {}
+class Orange implements FruitInterface {}
diff --git a/core/modules/tour/src/TipPluginManager.php b/core/modules/tour/src/TipPluginManager.php
index 6f98f62..1a66bbb 100644
--- a/core/modules/tour/src/TipPluginManager.php
+++ b/core/modules/tour/src/TipPluginManager.php
@@ -22,6 +22,11 @@
 class TipPluginManager extends DefaultPluginManager {
 
   /**
+   * {@inheritdoc}
+   */
+  protected $interface = '\Drupal\tour\TipPluginInterface';
+
+  /**
    * Constructs a new TipPluginManager.
    *
    * @param \Traversable $namespaces
diff --git a/core/modules/views/src/Form/ViewsExposedForm.php b/core/modules/views/src/Form/ViewsExposedForm.php
index 4bc76fd..fc01380 100644
--- a/core/modules/views/src/Form/ViewsExposedForm.php
+++ b/core/modules/views/src/Form/ViewsExposedForm.php
@@ -81,7 +81,7 @@ public function buildForm(array $form, FormStateInterface $form_state) {
 
     // Go through each handler and let it generate its exposed widget.
     foreach ($view->display_handler->handlers as $type => $value) {
-      /** @var \Drupal\views\Plugin\views\HandlerBase $handler */
+      /** @var \Drupal\views\Plugin\views\ViewsHandlerInterface $handler */
       foreach ($view->$type as $id => $handler) {
         if ($handler->canExpose() && $handler->isExposed()) {
           // Grouped exposed filters have their own forms.
@@ -134,7 +134,7 @@ public function buildForm(array $form, FormStateInterface $form_state) {
    */
   public function validateForm(array &$form, FormStateInterface $form_state) {
     foreach (array('field', 'filter') as $type) {
-      /** @var \Drupal\views\Plugin\views\HandlerBase[] $handlers */
+      /** @var \Drupal\views\Plugin\views\ViewsHandlerInterface[] $handlers */
       $handlers = &$form_state['view']->$type;
       foreach ($handlers as $key => $handler) {
         $handlers[$key]->validateExposed($form, $form_state);
@@ -150,7 +150,7 @@ public function validateForm(array &$form, FormStateInterface $form_state) {
    */
   public function submitForm(array &$form, FormStateInterface $form_state) {
     foreach (array('field', 'filter') as $type) {
-      /** @var \Drupal\views\Plugin\views\HandlerBase[] $handlers */
+      /** @var \Drupal\views\Plugin\views\ViewsHandlerInterface[] $handlers */
       $handlers = &$form_state['view']->$type;
       foreach ($handlers as $key => $info) {
         $handlers[$key]->submitExposed($form, $form_state);
diff --git a/core/modules/views/src/Plugin/ViewsHandlerManager.php b/core/modules/views/src/Plugin/ViewsHandlerManager.php
index 7b7b76e..0024a30 100644
--- a/core/modules/views/src/Plugin/ViewsHandlerManager.php
+++ b/core/modules/views/src/Plugin/ViewsHandlerManager.php
@@ -20,6 +20,11 @@
 class ViewsHandlerManager extends DefaultPluginManager {
 
   /**
+   * {@inheritdoc}
+   */
+  protected $interface = '\Drupal\views\Plugin\views\ViewsHandlerInterface';
+
+  /**
    * The views data cache.
    *
    * @var \Drupal\views\ViewsData
@@ -74,7 +79,7 @@ public function __construct($handler_type, \Traversable $namespaces, ViewsData $
    *   (optional) Override the actual handler object with this plugin ID. Used for
    *   aggregation when the handler is redirected to the aggregation handler.
    *
-   * @return \Drupal\views\Plugin\views\HandlerBase
+   * @return \Drupal\views\Plugin\views\ViewsHandlerInterface
    *   An instance of a handler object. May be a broken handler instance.
    */
   public function getHandler($item, $override = NULL) {
diff --git a/core/modules/views/src/Plugin/ViewsPluginManager.php b/core/modules/views/src/Plugin/ViewsPluginManager.php
index ca98555..ce70426 100644
--- a/core/modules/views/src/Plugin/ViewsPluginManager.php
+++ b/core/modules/views/src/Plugin/ViewsPluginManager.php
@@ -20,6 +20,11 @@
 class ViewsPluginManager extends DefaultPluginManager {
 
   /**
+   * {@inheritdoc}
+   */
+  protected $interface = '\Drupal\views\Plugin\views\ViewsPluginInterface';
+
+  /**
    * Constructs a ViewsPluginManager object.
    *
    * @param string $type
diff --git a/core/modules/views/src/Plugin/views/HandlerBase.php b/core/modules/views/src/Plugin/views/HandlerBase.php
index ce31f43..ef9759d 100644
--- a/core/modules/views/src/Plugin/views/HandlerBase.php
+++ b/core/modules/views/src/Plugin/views/HandlerBase.php
@@ -16,7 +16,6 @@
 use Drupal\Core\Render\Element;
 use Drupal\Core\Session\AccountInterface;
 use Drupal\views\Plugin\views\display\DisplayPluginBase;
-use Drupal\views\Plugin\views\PluginBase;
 use Drupal\views\ViewExecutable;
 use Drupal\Core\Database\Database;
 use Drupal\views\Views;
@@ -27,7 +26,7 @@
  *
  * @ingroup views_plugins
  */
-abstract class HandlerBase extends PluginBase {
+abstract class HandlerBase extends PluginBase implements ViewsHandlerInterface {
 
   /**
    * Where the $query object will reside:
@@ -109,7 +108,7 @@ public function __construct(array $configuration, $plugin_id, $plugin_definition
   }
 
   /**
-   * Overrides \Drupal\views\Plugin\views\PluginBase::init().
+   * {@inheritdoc}
    */
   public function init(ViewExecutable $view, DisplayPluginBase $display, array &$options = NULL) {
     parent::init($view, $display, $options);
@@ -172,7 +171,7 @@ protected function defineOptions() {
   }
 
   /**
-   * Return a string representing this handler's name in the UI.
+   * {@inheritdoc}
    */
   public function adminLabel($short = FALSE) {
     if (!empty($this->options['admin_label'])) {
@@ -184,11 +183,7 @@ public function adminLabel($short = FALSE) {
   }
 
   /**
-   * Shortcut to get a handler's raw field value.
-   *
-   * This should be overridden for handlers with formulae or other
-   * non-standard fields. Because this takes an argument, fields
-   * overriding this can just call return parent::getField($formula)
+   * {@inheritdoc}
    */
   public function getField($field = NULL) {
     if (!isset($field)) {
@@ -218,15 +213,7 @@ public function getField($field = NULL) {
   }
 
   /**
-   * Sanitize the value for output.
-   *
-   * @param $value
-   *   The value being rendered.
-   * @param $type
-   *   The type of sanitization needed. If not provided, String::checkPlain() is used.
-   *
-   * @return string
-   *   Returns the safe value.
+   * {@inheritdoc}
    */
   public function sanitizeValue($value, $type = NULL) {
     switch ($type) {
@@ -277,7 +264,7 @@ protected function caseTransform($string, $option) {
   }
 
   /**
-   * Build the options form.
+   * {@inheritdoc}
    */
   public function buildOptionsForm(&$form, FormStateInterface $form_state) {
     // Some form elements belong in a fieldset for presentation, but can't
@@ -332,23 +319,21 @@ protected function getModuleHandler() {
   }
 
   /**
-   * Sets the module handler.
-   *
-   * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
-   *   The module handler.
+   * {@inheritdoc}
    */
   public function setModuleHandler(ModuleHandlerInterface $module_handler) {
     $this->moduleHandler = $module_handler;
   }
 
   /**
-   * Provides the handler some groupby.
+   * {@inheritdoc}
    */
   public function usesGroupBy() {
     return TRUE;
   }
+
   /**
-   * Provide a form for aggregation settings.
+   * {@inheritdoc}
    */
   public function buildGroupByForm(&$form, FormStateInterface $form_state) {
     $display_id = $form_state['display_id'];
@@ -373,94 +358,89 @@ public function buildGroupByForm(&$form, FormStateInterface $form_state) {
   }
 
   /**
-   * Perform any necessary changes to the form values prior to storage.
-   * There is no need for this function to actually store the data.
+   * {@inheritdoc}
    */
   public function submitGroupByForm(&$form, FormStateInterface $form_state) {
     $form_state['handler']->options['group_type'] = $form_state->getValue(array('options', 'group_type'));
   }
 
   /**
-   * If a handler has 'extra options' it will get a little settings widget and
-   * another form called extra_options.
+   * {@inheritdoc}
    */
   public function hasExtraOptions() { return FALSE; }
 
   /**
-   * Provide defaults for the handler.
+   * {@inheritdoc}
    */
   public function defineExtraOptions(&$option) { }
 
   /**
-   * Provide a form for setting options.
+   * {@inheritdoc}
    */
   public function buildExtraOptionsForm(&$form, FormStateInterface $form_state) { }
 
   /**
-   * Validate the options form.
+   * {@inheritdoc}
    */
   public function validateExtraOptionsForm($form, FormStateInterface $form_state) { }
 
   /**
-   * Perform any necessary changes to the form values prior to storage.
-   * There is no need for this function to actually store the data.
+   * {@inheritdoc}
    */
   public function submitExtraOptionsForm($form, FormStateInterface $form_state) { }
 
   /**
-   * Determine if a handler can be exposed.
+   * {@inheritdoc}
    */
   public function canExpose() { return FALSE; }
 
   /**
-   * Set new exposed option defaults when exposed setting is flipped
-   * on.
+   * {@inheritdoc}
    */
   public function defaultExposeOptions() { }
 
   /**
-   * Get information about the exposed form for the form renderer.
+   * {@inheritdoc}
    */
   public function exposedInfo() { }
 
   /**
-   * Render our chunk of the exposed handler form when selecting
+   * {@inheritdoc}
    */
   public function buildExposedForm(&$form, FormStateInterface $form_state) { }
 
   /**
-   * Validate the exposed handler form
+   * {@inheritdoc}
    */
   public function validateExposed(&$form, FormStateInterface $form_state) { }
 
   /**
-   * Submit the exposed handler form
+   * {@inheritdoc}
    */
   public function submitExposed(&$form, FormStateInterface $form_state) { }
 
   /**
-   * Form for exposed handler options.
+   * {@inheritdoc}
    */
   public function buildExposeForm(&$form, FormStateInterface $form_state) { }
 
   /**
-   * Validate the options form.
+   * {@inheritdoc}
    */
   public function validateExposeForm($form, FormStateInterface $form_state) { }
 
   /**
-   * Perform any necessary changes to the form exposes prior to storage.
-   * There is no need for this function to actually store the data.
+   * {@inheritdoc}
    */
   public function submitExposeForm($form, FormStateInterface $form_state) { }
 
   /**
-   * Shortcut to display the expose/hide button.
+   * {@inheritdoc}
    */
   public function showExposeButton(&$form, FormStateInterface $form_state) { }
 
   /**
-   * Shortcut to display the exposed options form.
+   * {@inheritdoc}
    */
   public function showExposeForm(&$form, FormStateInterface $form_state) {
     if (empty($this->options['exposed'])) {
@@ -483,10 +463,7 @@ public function showExposeForm(&$form, FormStateInterface $form_state) {
   }
 
   /**
-   * Check whether current user has access to this handler.
-   *
-   * @param AccountInterface $account
-   * @return boolean
+   * {@inheritdoc}
    */
   public function access(AccountInterface $account) {
     if (isset($this->definition['access callback']) && function_exists($this->definition['access callback'])) {
@@ -500,26 +477,19 @@ public function access(AccountInterface $account) {
   }
 
   /**
-   * Run before the view is built.
-   *
-   * This gives all the handlers some time to set up before any handler has
-   * been fully run.
+   * {@inheritdoc}
    */
   public function preQuery() {
   }
 
   /**
-   * Don't run a query by default.
+   * {@inheritdoc}
    */
   public function query() {
   }
 
   /**
-   * Run after the view is executed, before the result is cached.
-   *
-   * This gives all the handlers some time to modify values. This is primarily
-   * used so that handlers that pull up secondary data can put it in the
-   * $values so that the raw data can be utilized externally.
+   * {@inheritdoc}
    */
   public function postExecute(&$values) { }
 
@@ -534,8 +504,7 @@ protected function placeholder() {
   }
 
   /**
-   * Called just prior to query(), this lets a handler set up any relationship
-   * it needs.
+   * {@inheritdoc}
    */
   public function setRelationship() {
     // Ensure this gets set to something.
@@ -564,8 +533,7 @@ public function setRelationship() {
   }
 
   /**
-   * Ensure the main table for this handler is in the query. This is used
-   * a lot.
+   * {@inheritdoc}
    */
   public function ensureMyTable() {
     if (!isset($this->tableAlias)) {
@@ -575,48 +543,39 @@ public function ensureMyTable() {
   }
 
   /**
-   * Provide text for the administrative summary.
+   * {@inheritdoc}
    */
   public function adminSummary() { }
 
   /**
-   * Determine if this item is 'exposed', meaning it provides form elements
-   * to let users modify the view.
-   *
-   * @return TRUE/FALSE
+   * {@inheritdoc}
    */
   public function isExposed() {
     return !empty($this->options['exposed']);
   }
 
   /**
-   * Returns TRUE if the exposed filter works like a grouped filter.
+   * {@inheritdoc}
    */
   public function isAGroup() { return FALSE; }
 
   /**
-   * Define if the exposed input has to be submitted multiple times.
-   * This is TRUE when exposed filters grouped are using checkboxes as
-   * widgets.
+   * {@inheritdoc}
    */
   public function multipleExposedInput() { return FALSE; }
 
   /**
-   * Take input from exposed handlers and assign to this handler, if necessary.
+   * {@inheritdoc}
    */
   public function acceptExposedInput($input) { return TRUE; }
 
   /**
-   * If set to remember exposed input in the session, store it there.
+   * {@inheritdoc}
    */
   public function storeExposedInput($input, $status) { return TRUE; }
 
   /**
-   * Get the join object that should be used for this handler.
-   *
-   * This method isn't used a great deal, but it's very handy for easily
-   * getting the join if it is necessary to make some changes to it, such
-   * as adding an 'extra'.
+   * {@inheritdoc}
    */
   public function getJoin() {
     // get the join from this table that links back to the base table.
@@ -635,44 +594,26 @@ public function getJoin() {
   }
 
   /**
-   * Validates the handler against the complete View.
-   *
-   * This is called when the complete View is being validated. For validating
-   * the handler options form use validateOptionsForm().
-   *
-   * @see views_handler::validateOptionsForm()
-   *
-   * @return
-   *   Empty array if the handler is valid; an array of error strings if it is not.
+   * {@inheritdoc}
    */
   public function validate() { return array(); }
 
   /**
-   * Determines if the handler is considered 'broken', meaning it's a
-   * a placeholder used when a handler can't be found.
+   * {@inheritdoc}
    */
   public function broken() {
     return FALSE;
   }
 
   /**
-   * Creates cross-database SQL date formatting.
-   *
-   * @param string $format
-   *   A format string for the result, like 'Y-m-d H:i:s'.
-   *
-   * @return string
-   *   An appropriate SQL string for the DB type and field type.
+   * {@inheritdoc}
    */
   public function getDateFormat($format) {
     return $this->query->getDateFormat($this->getDateField(), $format);
   }
 
   /**
-   * Creates cross-database SQL dates.
-   *
-   * @return string
-   *   An appropriate SQL string for the db type and field type.
+   * {@inheritdoc}
    */
   public function getDateField() {
     return $this->query->getDateField("$this->tableAlias.$this->realField");
@@ -692,24 +633,14 @@ protected function getViewsData() {
   }
 
   /**
-   * Sets the views data service.
-   *
-   * @param \Drupal\views\ViewsData $views_data
-   *   The views data.
+   * {@inheritdoc}
    */
   public function setViewsData(ViewsData $views_data) {
     $this->viewsData = $views_data;
   }
 
   /**
-   * Fetches a handler to join one table to a primary table from the data cache.
-   *
-   * @param string $table
-   *   The table to join from.
-   * @param string $base_table
-   *   The table to join to.
-   *
-   * @return \Drupal\views\Plugin\views\join\JoinPluginBase
+   * {@inheritdoc}
    */
   public static function getTableJoin($table, $base_table) {
     $data = Views::viewsData()->get($table);
@@ -745,13 +676,7 @@ public static function getTableJoin($table, $base_table) {
   }
 
   /**
-   * Determines the entity type used by this handler.
-   *
-   * If this handler uses a relationship, the base class of the relationship is
-   * taken into account.
-   *
-   * @return string
-   *   The machine name of the entity type.
+   * {@inheritdoc}
    */
   public function getEntityType() {
     // If the user has configured a relationship on the handler take that into
@@ -772,15 +697,7 @@ public function getEntityType() {
   }
 
   /**
-   * Breaks x,y,z and x+y+z into an array.
-   *
-   * @param string $str
-   *   The string to split.
-   * @param bool $force_int
-   *   Enforce a numeric check.
-   *
-   * @return \stdClass
-   *   A stdClass object containing value and operator properties.
+   * {@inheritdoc}
    */
   public static function breakString($str, $force_int = FALSE) {
     $operator = NULL;
@@ -811,7 +728,7 @@ public static function breakString($str, $force_int = FALSE) {
   }
 
   /**
-   * Displays the Expose form.
+   * {@inheritdoc}
    */
   public function displayExposedForm($form, FormStateInterface $form_state) {
     $item = &$this->options;
@@ -834,8 +751,7 @@ public function displayExposedForm($form, FormStateInterface $form_state) {
   }
 
   /**
-   * A submit handler that is used for storing temporary items when using
-   * multi-step changes, such as ajax requests.
+   * {@inheritdoc}
    */
   public function submitTemporaryForm($form, FormStateInterface $form_state) {
     // Run it through the handler's submit function.
diff --git a/core/modules/views/src/Plugin/views/PluginBase.php b/core/modules/views/src/Plugin/views/PluginBase.php
index 132ceec..ffc8b23 100644
--- a/core/modules/views/src/Plugin/views/PluginBase.php
+++ b/core/modules/views/src/Plugin/views/PluginBase.php
@@ -41,7 +41,7 @@
  *
  * @ingroup views_plugins
  */
-abstract class PluginBase extends ComponentPluginBase implements ContainerFactoryPluginInterface {
+abstract class PluginBase extends ComponentPluginBase implements ContainerFactoryPluginInterface, ViewsPluginInterface {
 
   /**
    * Options for this plugin will be held here.
@@ -100,14 +100,7 @@ public static function create(ContainerInterface $container, array $configuratio
   }
 
   /**
-   * Initialize the plugin.
-   *
-   * @param \Drupal\views\ViewExecutable $view
-   *   The view object.
-   * @param \Drupal\views\Plugin\views\display\DisplayPluginBase $display
-   *   The display handler.
-   * @param array $options
-   *   The options configured for this plugin.
+   * {@inheritdoc}
    */
   public function init(ViewExecutable $view, DisplayPluginBase $display, array &$options = NULL) {
     $this->view = $view;
@@ -163,8 +156,7 @@ protected function setOptionDefaults(array &$storage, array $options) {
   }
 
   /**
-   * Unpack options over our existing defaults, drilling down into arrays
-   * so that defaults don't get totally blown away.
+   * {@inheritdoc}
    */
   public function unpackOptions(&$storage, $options, $definition = NULL, $all = TRUE, $check = TRUE) {
     if ($check && !is_array($options)) {
@@ -203,19 +195,14 @@ public function unpackOptions(&$storage, $options, $definition = NULL, $all = TR
   }
 
   /**
-   * Clears a plugin.
+   * {@inheritdoc}
    */
   public function destroy() {
     unset($this->view, $this->display, $this->query);
   }
 
   /**
-   * Init will be called after construct, when the plugin is attached to a
-   * view and a display.
-   */
-
-  /**
-   * Provide a form to edit options for this plugin.
+   * {@inheritdoc}
    */
   public function buildOptionsForm(&$form, FormStateInterface $form_state) {
     // Some form elements belong in a fieldset for presentation, but can't
@@ -226,47 +213,41 @@ public function buildOptionsForm(&$form, FormStateInterface $form_state) {
   }
 
   /**
-   * Validate the options form.
+   * {@inheritdoc}
    */
   public function validateOptionsForm(&$form, FormStateInterface $form_state) { }
 
   /**
-   * Handle any special handling on the validate form.
+   * {@inheritdoc}
    */
   public function submitOptionsForm(&$form, FormStateInterface $form_state) { }
 
   /**
-   * Add anything to the query that we might need to.
+   * {@inheritdoc}
    */
   public function query() { }
 
   /**
-   * Provide a full list of possible theme templates used by this style.
+   * {@inheritdoc}
    */
   public function themeFunctions() {
     return $this->view->buildThemeFunctions($this->definition['theme']);
   }
 
   /**
-   * Validate that the plugin is correct and can be saved.
-   *
-   * @return
-   *   An array of error strings to tell the user what is wrong with this
-   *   plugin.
+   * {@inheritdoc}
    */
   public function validate() { return array(); }
 
   /**
-   * Returns the summary of the settings in the display.
+   * {@inheritdoc}
    */
   public function summaryTitle() {
     return t('Settings');
   }
 
   /**
-   * Return the human readable name of the display.
-   *
-   * This appears on the ui beside each plugin and beside the settings link.
+   * {@inheritdoc}
    */
   public function pluginTitle() {
     // Short_title is optional so its defaults to an empty string.
@@ -277,39 +258,21 @@ public function pluginTitle() {
   }
 
   /**
-   * Returns the usesOptions property.
+   * {@inheritdoc}
    */
   public function usesOptions() {
     return $this->usesOptions;
   }
 
   /**
-   * Returns a string with any core tokens replaced.
-   *
-   * @param string $string
-   *   The string to preform the token replacement on.
-   * @param array $options
-   *   An array of options, as passed to \Drupal\Core\Utility\Token::replace().
-   *
-   * @return string
-   *   The tokenized string.
+   * {@inheritdoc}
    */
   public function globalTokenReplace($string = '', array $options = array()) {
     return \Drupal::token()->replace($string, array('view' => $this->view), $options);
   }
 
   /**
-   * Returns an array of available token replacements.
-   *
-   * @param bool $prepared
-   *   Whether to return the raw token info for each token or an array of
-   *   prepared tokens for each type. E.g. "[view:name]".
-   * @param array $types
-   *   An array of additional token types to return, defaults to 'site' and
-   *   'view'.
-   *
-   * @return array
-   *   An array of available token replacement info or tokens, grouped by type.
+   * {@inheritdoc}
    */
   public function getAvailableGlobalTokens($prepared = FALSE, array $types = array()) {
     $info = \Drupal::token()->getInfo();
@@ -333,12 +296,7 @@ public function getAvailableGlobalTokens($prepared = FALSE, array $types = array
   }
 
   /**
-   * Adds elements for available core tokens to a form.
-   *
-   * @param array $form
-   *   The form array to alter, passed by reference.
-   * @param \Drupal\Core\Form\FormStateInterface $form_state
-   *   The current state of the form.
+   * {@inheritdoc}
    */
   public function globalTokenForm(&$form, FormStateInterface $form_state) {
     $token_items = array();
@@ -369,19 +327,7 @@ public function globalTokenForm(&$form, FormStateInterface $form_state) {
   }
 
   /**
-   * Moves form elements into fieldsets for presentation purposes.
-   *
-   * Many views forms use #tree = TRUE to keep their values in a hierarchy for
-   * easier storage. Moving the form elements into fieldsets during form
-   * building would break up that hierarchy. Therefore, we wait until the
-   * pre_render stage, where any changes we make affect presentation only and
-   * aren't reflected in $form_state->getValues().
-   *
-   * @param array $form
-   *   The form build array to alter.
-   *
-   * @return array
-   *   The form build array.
+   * {@inheritdoc}
    */
   public static function preRenderAddFieldsetMarkup(array $form) {
     foreach (Element::children($form) as $key) {
@@ -400,17 +346,7 @@ public static function preRenderAddFieldsetMarkup(array $form) {
   }
 
   /**
-   * Flattens the structure of form elements.
-   *
-   * If a form element has #flatten = TRUE, then all of it's children get moved
-   * to the same level as the element itself. So $form['to_be_flattened'][$key]
-   * becomes $form[$key], and $form['to_be_flattened'] gets unset.
-   *
-   * @param array $form
-   *   The form build array to alter.
-   *
-   * @return array
-   *   The form build array.
+   * {@inheritdoc}
    */
   public static function preRenderFlattenData($form) {
     foreach (Element::children($form) as $key) {
@@ -428,12 +364,7 @@ public static function preRenderFlattenData($form) {
   }
 
   /**
-   * Returns an array of module dependencies for this plugin.
-   *
-   * Dependencies are a list of module names, which might depend on the
-   * configuration.
-   *
-   * @return array
+   * {@inheritdoc}
    */
   public function getDependencies() {
     return array();
diff --git a/core/modules/views/src/Plugin/views/ViewsHandlerInterface.php b/core/modules/views/src/Plugin/views/ViewsHandlerInterface.php
new file mode 100644
index 0000000..45181e6
--- /dev/null
+++ b/core/modules/views/src/Plugin/views/ViewsHandlerInterface.php
@@ -0,0 +1,312 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\views\Plugin\views\ViewsHandlerInterface.
+ */
+
+namespace Drupal\views\Plugin\views;
+
+use Drupal\Core\Extension\ModuleHandlerInterface;
+use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\Session\AccountInterface;
+use Drupal\views\ViewsData;
+
+/**
+ * Provides an interface for all views handlers.
+ */
+interface ViewsHandlerInterface extends ViewsPluginInterface {
+
+  /**
+   * Shortcut to display the expose/hide button.
+   */
+  public function showExposeButton(&$form, FormStateInterface $form_state);
+
+  /**
+   * Shortcut to get a handler's raw field value.
+   *
+   * This should be overridden for handlers with formulae or other
+   * non-standard fields. Because this takes an argument, fields
+   * overriding this can just call return parent::getField($formula)
+   */
+  public function getField($field = NULL);
+
+  /**
+   * A submit handler that is used for storing temporary items when using
+   * multi-step changes, such as ajax requests.
+   */
+  public function submitTemporaryForm($form, FormStateInterface $form_state);
+
+  /**
+   * Returns TRUE if the exposed filter works like a grouped filter.
+   */
+  public function isAGroup();
+
+  /**
+   * Provide a form for setting options.
+   */
+  public function buildExtraOptionsForm(&$form, FormStateInterface $form_state);
+
+  /**
+   * Displays the Expose form.
+   */
+  public function displayExposedForm($form, FormStateInterface $form_state);
+
+  /**
+   * Run before the view is built.
+   *
+   * This gives all the handlers some time to set up before any handler has
+   * been fully run.
+   */
+  public function preQuery();
+
+  /**
+   * Validate the options form.
+   */
+  public function validateExposeForm($form, FormStateInterface $form_state);
+
+  /**
+   * Determines the entity type used by this handler.
+   *
+   * If this handler uses a relationship, the base class of the relationship is
+   * taken into account.
+   *
+   * @return string
+   *   The machine name of the entity type.
+   */
+  public function getEntityType();
+
+  /**
+   * Determines if the handler is considered 'broken', meaning it's a
+   * a placeholder used when a handler can't be found.
+   */
+  public function broken();
+
+  /**
+   * Sets the module handler.
+   *
+   * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
+   *   The module handler.
+   */
+  public function setModuleHandler(ModuleHandlerInterface $module_handler);
+
+  /**
+   * Ensure the main table for this handler is in the query. This is used
+   * a lot.
+   */
+  public function ensureMyTable();
+
+  /**
+   * Check whether current user has access to this handler.
+   *
+   * @param AccountInterface $account
+   *
+   * @return boolean
+   */
+  public function access(AccountInterface $account);
+
+  /**
+   * Get the join object that should be used for this handler.
+   *
+   * This method isn't used a great deal, but it's very handy for easily
+   * getting the join if it is necessary to make some changes to it, such
+   * as adding an 'extra'.
+   */
+  public function getJoin();
+
+  /**
+   * Take input from exposed handlers and assign to this handler, if necessary.
+   */
+  public function acceptExposedInput($input);
+
+  /**
+   * Define if the exposed input has to be submitted multiple times.
+   * This is TRUE when exposed filters grouped are using checkboxes as
+   * widgets.
+   */
+  public function multipleExposedInput();
+
+  /**
+   * Render our chunk of the exposed handler form when selecting
+   */
+  public function buildExposedForm(&$form, FormStateInterface $form_state);
+
+  /**
+   * Perform any necessary changes to the form values prior to storage.
+   * There is no need for this function to actually store the data.
+   */
+  public function submitGroupByForm(&$form, FormStateInterface $form_state);
+
+  /**
+   * Perform any necessary changes to the form values prior to storage.
+   * There is no need for this function to actually store the data.
+   */
+  public function submitExtraOptionsForm($form, FormStateInterface $form_state);
+
+  /**
+   * Sanitize the value for output.
+   *
+   * @param $value
+   *   The value being rendered.
+   * @param $type
+   *   The type of sanitization needed. If not provided, String::checkPlain() is used.
+   *
+   * @return string
+   *   Returns the safe value.
+   */
+  public function sanitizeValue($value, $type = NULL);
+
+  /**
+   * Creates cross-database SQL dates.
+   *
+   * @return string
+   *   An appropriate SQL string for the db type and field type.
+   */
+  public function getDateField();
+
+  /**
+   * Perform any necessary changes to the form exposes prior to storage.
+   * There is no need for this function to actually store the data.
+   */
+  public function submitExposeForm($form, FormStateInterface $form_state);
+
+  /**
+   * Validate the options form.
+   */
+  public function validateExtraOptionsForm($form, FormStateInterface $form_state);
+
+  /**
+   * Fetches a handler to join one table to a primary table from the data cache.
+   *
+   * @param string $table
+   *   The table to join from.
+   * @param string $base_table
+   *   The table to join to.
+   *
+   * @return \Drupal\views\Plugin\views\join\JoinPluginBase
+   */
+  public static function getTableJoin($table, $base_table);
+
+  /**
+   * Submit the exposed handler form
+   */
+  public function submitExposed(&$form, FormStateInterface $form_state);
+
+  /**
+   * Creates cross-database SQL date formatting.
+   *
+   * @param string $format
+   *   A format string for the result, like 'Y-m-d H:i:s'.
+   *
+   * @return string
+   *   An appropriate SQL string for the DB type and field type.
+   */
+  public function getDateFormat($format);
+
+  /**
+   * Run after the view is executed, before the result is cached.
+   *
+   * This gives all the handlers some time to modify values. This is primarily
+   * used so that handlers that pull up secondary data can put it in the
+   * $values so that the raw data can be utilized externally.
+   */
+  public function postExecute(&$values);
+
+  /**
+   * Shortcut to display the exposed options form.
+   */
+  public function showExposeForm(&$form, FormStateInterface $form_state);
+
+  /**
+   * Called just prior to query(), this lets a handler set up any relationship
+   * it needs.
+   */
+  public function setRelationship();
+
+  /**
+   * Provide defaults for the handler.
+   */
+  public function defineExtraOptions(&$option);
+
+  /**
+   * If set to remember exposed input in the session, store it there.
+   */
+  public function storeExposedInput($input, $status);
+
+  /**
+   * Return a string representing this handler's name in the UI.
+   */
+  public function adminLabel($short = FALSE);
+
+  /**
+   * Determine if this item is 'exposed', meaning it provides form elements
+   * to let users modify the view.
+   *
+   * @return TRUE/FALSE
+   */
+  public function isExposed();
+
+  /**
+   * Sets the views data service.
+   *
+   * @param \Drupal\views\ViewsData $views_data
+   *   The views data.
+   */
+  public function setViewsData(ViewsData $views_data);
+
+  /**
+   * Set new exposed option defaults when exposed setting is flipped
+   * on.
+   */
+  public function defaultExposeOptions();
+
+  /**
+   * Form for exposed handler options.
+   */
+  public function buildExposeForm(&$form, FormStateInterface $form_state);
+
+  /**
+   * Breaks x,y,z and x+y+z into an array.
+   *
+   * @param string $str
+   *   The string to split.
+   * @param bool $force_int
+   *   Enforce a numeric check.
+   *
+   * @return \stdClass
+   *   A stdClass object containing value and operator properties.
+   */
+  public static function breakString($str, $force_int = FALSE);
+
+  /**
+   * Determine if a handler can be exposed.
+   */
+  public function canExpose();
+
+  /**
+   * Provide text for the administrative summary.
+   */
+  public function adminSummary();
+
+  /**
+   * Validate the exposed handler form
+   */
+  public function validateExposed(&$form, FormStateInterface $form_state);
+
+  /**
+   * If a handler has 'extra options' it will get a little settings widget and
+   * another form called extra_options.
+   */
+  public function hasExtraOptions();
+
+  /**
+   * Provide a form for aggregation settings.
+   */
+  public function buildGroupByForm(&$form, FormStateInterface $form_state);
+
+  /**
+   * Get information about the exposed form for the form renderer.
+   */
+  public function exposedInfo();
+
+}
diff --git a/core/modules/views/src/Plugin/views/ViewsPluginInterface.php b/core/modules/views/src/Plugin/views/ViewsPluginInterface.php
new file mode 100644
index 0000000..df5de7a
--- /dev/null
+++ b/core/modules/views/src/Plugin/views/ViewsPluginInterface.php
@@ -0,0 +1,181 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\views\Plugin\views\ViewsPluginInterface.
+ */
+
+namespace Drupal\views\Plugin\views;
+
+use Drupal\Component\Plugin\DerivativeInspectionInterface;
+use Drupal\Component\Plugin\PluginInspectionInterface;
+use Drupal\Core\Form\FormStateInterface;
+use Drupal\views\Plugin\views\display\DisplayPluginBase;
+use Drupal\views\ViewExecutable;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+
+/**
+ * Provides an interface for all views plugins.
+ */
+interface ViewsPluginInterface extends PluginInspectionInterface, DerivativeInspectionInterface {
+
+  /**
+   * Returns an array of module dependencies for this plugin.
+   *
+   * Dependencies are a list of module names, which might depend on the
+   * configuration.
+   *
+   * @return array
+   */
+  public function getDependencies();
+
+  /**
+   * Return the human readable name of the display.
+   *
+   * This appears on the ui beside each plugin and beside the settings link.
+   */
+  public function pluginTitle();
+
+  /**
+   * Returns the usesOptions property.
+   */
+  public function usesOptions();
+
+  /**
+   * Validate the options form.
+   */
+  public function validateOptionsForm(&$form, FormStateInterface $form_state);
+
+  /**
+   * Returns the summary of the settings in the display.
+   */
+  public function summaryTitle();
+
+  /**
+   * Moves form elements into fieldsets for presentation purposes.
+   *
+   * Many views forms use #tree = TRUE to keep their values in a hierarchy for
+   * easier storage. Moving the form elements into fieldsets during form
+   * building would break up that hierarchy. Therefore, we wait until the
+   * pre_render stage, where any changes we make affect presentation only and
+   * aren't reflected in $form_state->getValues().
+   *
+   * @param array $form
+   *   The form build array to alter.
+   *
+   * @return array
+   *   The form build array.
+   */
+  public static function preRenderAddFieldsetMarkup(array $form);
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition);
+
+  /**
+   * Initialize the plugin.
+   *
+   * @param \Drupal\views\ViewExecutable $view
+   *   The view object.
+   * @param \Drupal\views\Plugin\views\display\DisplayPluginBase $display
+   *   The display handler.
+   * @param array $options
+   *   The options configured for this plugin.
+   */
+  public function init(ViewExecutable $view, DisplayPluginBase $display, array &$options = NULL);
+
+  /**
+   * Handle any special handling on the validate form.
+   */
+  public function submitOptionsForm(&$form, FormStateInterface $form_state);
+
+  /**
+   * Adds elements for available core tokens to a form.
+   *
+   * @param array $form
+   *   The form array to alter, passed by reference.
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
+   *   The current state of the form.
+   */
+  public function globalTokenForm(&$form, FormStateInterface $form_state);
+
+  /**
+   * Returns an array of available token replacements.
+   *
+   * @param bool $prepared
+   *   Whether to return the raw token info for each token or an array of
+   *   prepared tokens for each type. E.g. "[view:name]".
+   * @param array $types
+   *   An array of additional token types to return, defaults to 'site' and
+   *   'view'.
+   *
+   * @return array
+   *   An array of available token replacement info or tokens, grouped by type.
+   */
+  public function getAvailableGlobalTokens($prepared = FALSE, array $types = array());
+
+  /**
+   * Flattens the structure of form elements.
+   *
+   * If a form element has #flatten = TRUE, then all of it's children get moved
+   * to the same level as the element itself. So $form['to_be_flattened'][$key]
+   * becomes $form[$key], and $form['to_be_flattened'] gets unset.
+   *
+   * @param array $form
+   *   The form build array to alter.
+   *
+   * @return array
+   *   The form build array.
+   */
+  public static function preRenderFlattenData($form);
+
+  /**
+   * Returns a string with any core tokens replaced.
+   *
+   * @param string $string
+   *   The string to preform the token replacement on.
+   * @param array $options
+   *   An array of options, as passed to \Drupal\Core\Utility\Token::replace().
+   *
+   * @return string
+   *   The tokenized string.
+   */
+  public function globalTokenReplace($string = '', array $options = array());
+
+  /**
+   * Clears a plugin.
+   */
+  public function destroy();
+
+  /**
+   * Validate that the plugin is correct and can be saved.
+   *
+   * @return
+   *   An array of error strings to tell the user what is wrong with this
+   *   plugin.
+   */
+  public function validate();
+
+  /**
+   * Add anything to the query that we might need to.
+   */
+  public function query();
+
+  /**
+   * Unpack options over our existing defaults, drilling down into arrays
+   * so that defaults don't get totally blown away.
+   */
+  public function unpackOptions(&$storage, $options, $definition = NULL, $all = TRUE, $check = TRUE);
+
+  /**
+   * Provide a form to edit options for this plugin.
+   */
+  public function buildOptionsForm(&$form, FormStateInterface $form_state);
+
+  /**
+   * Provide a full list of possible theme templates used by this style.
+   */
+  public function themeFunctions();
+
+}
diff --git a/core/modules/views/src/Plugin/views/display/DisplayPluginBase.php b/core/modules/views/src/Plugin/views/display/DisplayPluginBase.php
index 31f30bc..9a3b7bf 100644
--- a/core/modules/views/src/Plugin/views/display/DisplayPluginBase.php
+++ b/core/modules/views/src/Plugin/views/display/DisplayPluginBase.php
@@ -837,7 +837,7 @@ public function usesFields() {
    * @param string $type
    *   The type of the plugin.
    *
-   * @return \Drupal\views\Plugin\views\PluginBase
+   * @return \Drupal\views\Plugin\views\ViewsPluginInterface
    */
   public function getPlugin($type) {
     // Look up the plugin name to use for this instance.
@@ -890,7 +890,7 @@ public function &getHandler($type, $id) {
   /**
    * Get a full array of handlers for $type. This caches them.
    *
-   * @return \Drupal\views\Plugin\views\HandlerBase[]
+   * @return \Drupal\views\Plugin\views\ViewsHandlerInterface[]
    */
   public function getHandlers($type) {
     if (!isset($this->handlers[$type])) {
diff --git a/core/modules/views/src/Tests/Handler/HandlerTest.php b/core/modules/views/src/Tests/Handler/HandlerTest.php
index 9c9e038..b182dee 100644
--- a/core/modules/views/src/Tests/Handler/HandlerTest.php
+++ b/core/modules/views/src/Tests/Handler/HandlerTest.php
@@ -204,16 +204,14 @@ public function testHandlerWeights() {
       $loaded_order = array_keys($view->display_handler->getOption($type));
       $this->assertIdentical($original_order[$type], $loaded_order);
     }
-
   }
 
-
   /**
    * Check to see if a value is the same as the value on a certain handler.
    *
    * @param $expected
    *   The expected value to check.
-   * @param \Drupal\views\Plugin\views\HandlerBase $handler
+   * @param \Drupal\views\Plugin\views\ViewsHandlerInterface $handler
    *   The handler that has the $handler->value property to compare with first.
    * @param string $message
    *   The message to display along with the assertion.
diff --git a/core/tests/Drupal/Tests/Core/Plugin/DefaultPluginManagerTest.php b/core/tests/Drupal/Tests/Core/Plugin/DefaultPluginManagerTest.php
index 7f7d3ac..c337533 100644
--- a/core/tests/Drupal/Tests/Core/Plugin/DefaultPluginManagerTest.php
+++ b/core/tests/Drupal/Tests/Core/Plugin/DefaultPluginManagerTest.php
@@ -13,6 +13,8 @@
  * Tests the DefaultPluginManager.
  *
  * @group Plugin
+ *
+ * @coversDefaultClass \Drupal\Core\Plugin\DefaultPluginManager
  */
 class DefaultPluginManagerTest extends UnitTestCase {
 
@@ -76,7 +78,7 @@ public function testDefaultPluginManagerWithDisabledModule() {
       ->with('disabled_module')
       ->will($this->returnValue(FALSE));
 
-    $plugin_manager = new TestPluginManager($this->namespaces, $definitions, $module_handler, 'test_alter_hook');
+    $plugin_manager = new TestPluginManager($this->namespaces, $definitions, $module_handler, 'test_alter_hook', '\Drupal\plugin_test\Plugin\plugin_test\fruit\FruitInterface');
 
     $this->assertEmpty($plugin_manager->getDefinition('cherry', FALSE), 'Plugin information of a disabled module is not available');
   }
@@ -101,7 +103,7 @@ public function testDefaultPluginManagerWithObjects() {
       ->with('disabled_module')
       ->will($this->returnValue(FALSE));
 
-    $plugin_manager = new TestPluginManager($this->namespaces, $definitions, $module_handler, 'test_alter_hook');
+    $plugin_manager = new TestPluginManager($this->namespaces, $definitions, $module_handler, 'test_alter_hook', '\Drupal\plugin_test\Plugin\plugin_test\fruit\FruitInterface');
 
     $this->assertEmpty($plugin_manager->getDefinition('cherry', FALSE), 'Plugin information is available');
   }
@@ -110,7 +112,7 @@ public function testDefaultPluginManagerWithObjects() {
    * Tests the plugin manager with no cache and altering.
    */
   public function testDefaultPluginManager() {
-    $plugin_manager = new TestPluginManager($this->namespaces, $this->expectedDefinitions);
+    $plugin_manager = new TestPluginManager($this->namespaces, $this->expectedDefinitions, NULL, NULL, '\Drupal\plugin_test\Plugin\plugin_test\fruit\FruitInterface');
     $this->assertEquals($this->expectedDefinitions, $plugin_manager->getDefinitions());
     $this->assertEquals($this->expectedDefinitions['banana'], $plugin_manager->getDefinition('banana'));
   }
@@ -129,7 +131,7 @@ public function testDefaultPluginManagerWithAlter() {
       ->method('alter')
       ->with($this->equalTo($alter_hook_name), $this->equalTo($this->expectedDefinitions));
 
-    $plugin_manager = new TestPluginManager($this->namespaces, $this->expectedDefinitions, $module_handler, $alter_hook_name);
+    $plugin_manager = new TestPluginManager($this->namespaces, $this->expectedDefinitions, $module_handler, $alter_hook_name, '\Drupal\plugin_test\Plugin\plugin_test\fruit\FruitInterface');
 
     $this->assertEquals($this->expectedDefinitions, $plugin_manager->getDefinitions());
     $this->assertEquals($this->expectedDefinitions['banana'], $plugin_manager->getDefinition('banana'));
@@ -153,7 +155,7 @@ public function testDefaultPluginManagerWithEmptyCache() {
       ->method('set')
       ->with($cid, $this->expectedDefinitions);
 
-    $plugin_manager = new TestPluginManager($this->namespaces, $this->expectedDefinitions);
+    $plugin_manager = new TestPluginManager($this->namespaces, $this->expectedDefinitions, NULL, NULL, '\Drupal\plugin_test\Plugin\plugin_test\fruit\FruitInterface');
     $plugin_manager->setCacheBackend($cache_backend, $cid);
 
     $this->assertEquals($this->expectedDefinitions, $plugin_manager->getDefinitions());
@@ -177,7 +179,7 @@ public function testDefaultPluginManagerWithFilledCache() {
       ->expects($this->never())
       ->method('set');
 
-    $plugin_manager = new TestPluginManager($this->namespaces, $this->expectedDefinitions);
+    $plugin_manager = new TestPluginManager($this->namespaces, $this->expectedDefinitions, NULL, NULL, '\Drupal\plugin_test\Plugin\plugin_test\fruit\FruitInterface');
     $plugin_manager->setCacheBackend($cache_backend, $cid);
 
     $this->assertEquals($this->expectedDefinitions, $plugin_manager->getDefinitions());
@@ -201,12 +203,57 @@ public function testCacheClearWithTags() {
 
     $this->getContainerWithCacheBins($cache_backend);
 
-    $plugin_manager = new TestPluginManager($this->namespaces, $this->expectedDefinitions);
+    $plugin_manager = new TestPluginManager($this->namespaces, $this->expectedDefinitions, NULL, NULL, '\Drupal\plugin_test\Plugin\plugin_test\fruit\FruitInterface');
     $plugin_manager->setCacheBackend($cache_backend, $cid, array('tag' => TRUE));
 
     $plugin_manager->clearCachedDefinitions();
   }
 
+  /**
+   * Tests plugins with the proper interface.
+   *
+   * @covers ::getDefinitions
+   * @covers ::enforcePluginInterface
+   */
+  public function testGetDefinitionsWithJustValidInterfaces() {
+    $plugin_manager = new TestPluginManager($this->namespaces, $this->expectedDefinitions, NULL, NULL, '\Drupal\plugin_test\Plugin\plugin_test\fruit\FruitInterface');
+
+    $definitions = $plugin_manager->getDefinitions();
+    $this->assertCount(2, $definitions);
+    $this->assertEquals($definitions, $this->expectedDefinitions);
+  }
+
+  /**
+   * Tests plugins without the proper interface.
+   *
+   * @covers ::getDefinitions
+   * @covers ::enforcePluginInterface
+   *
+   * @expectedException \Drupal\Component\Plugin\Exception\PluginException
+   * @expectedExceptionMessage Plugin kale in plugin_test should implement interface \Drupal\plugin_test\Plugin\plugin_test\fruit\FruitInterface
+   */
+  public function testGetDefinitionsWithInvalidInterfaces() {
+    $module_handler = $this->getMock('Drupal\Core\Extension\ModuleHandlerInterface');
+
+    $module_handler->expects($this->any())
+      ->method('moduleExists')
+      ->with('plugin_test')
+      ->willReturn(FALSE);
+
+    $this->expectedDefinitions['kale'] = array(
+      'id' => 'kale',
+      'label' => 'Kale',
+      'color' => 'green',
+      'class' => 'Drupal\plugin_test\Plugin\plugin_test\fruit\Kale',
+      'provider' => 'plugin_test',
+    );
+    $this->expectedDefinitions['apple']['provider'] = 'plugin_test';
+    $this->expectedDefinitions['banana']['provider'] = 'plugin_test';
+
+    $plugin_manager = new TestPluginManager($this->namespaces, $this->expectedDefinitions, $module_handler, NULL, '\Drupal\plugin_test\Plugin\plugin_test\fruit\FruitInterface');
+    $plugin_manager->getDefinitions();
+  }
+
 }
 
 if (!defined('DRUPAL_ROOT')) {
diff --git a/core/tests/Drupal/Tests/Core/Plugin/TestPluginManager.php b/core/tests/Drupal/Tests/Core/Plugin/TestPluginManager.php
index a7ea79d..d6c6384 100644
--- a/core/tests/Drupal/Tests/Core/Plugin/TestPluginManager.php
+++ b/core/tests/Drupal/Tests/Core/Plugin/TestPluginManager.php
@@ -28,8 +28,10 @@ class TestPluginManager extends DefaultPluginManager {
    *   (optional) The module handler to invoke the alter hook with.
    * @param string $alter_hook
    *   (optional) Name of the alter hook.
+   * @param string $interface
+   *   (optional) The interface required for the plugins.
    */
-  public function __construct(\Traversable $namespaces, array $definitions, ModuleHandlerInterface $module_handler = NULL, $alter_hook = NULL) {
+  public function __construct(\Traversable $namespaces, array $definitions, ModuleHandlerInterface $module_handler = NULL, $alter_hook = NULL, $interface = NULL) {
     // Create the object that can be used to return definitions for all the
     // plugins available for this type. Most real plugin managers use a richer
     // discovery implementation, but StaticDiscovery lets us add some simple
@@ -46,6 +48,7 @@ public function __construct(\Traversable $namespaces, array $definitions, Module
     if ($alter_hook) {
       $this->alterInfo($alter_hook);
     }
+    $this->interface = $interface;
   }
 
 }
