diff --git a/core/core.services.yml b/core/core.services.yml
index 91a2c2b..7e368e9 100644
--- a/core/core.services.yml
+++ b/core/core.services.yml
@@ -154,7 +154,7 @@ services:
     class: Drupal\Core\Config\InstallStorage
   config.typed:
     class: Drupal\Core\Config\TypedConfigManager
-    arguments: ['@config.storage', '@config.storage.schema', '@cache.discovery', '@module_handler']
+    arguments: ['@config.storage', '@config.storage.schema', '@cache.discovery', '@module_handler', '@event_dispatcher']
     tags:
       - { name: plugin_manager_cache_clear }
   context.handler:
@@ -284,7 +284,7 @@ services:
       - [setContainer, ['@service_container']]
   default_plugin_manager:
     abstract: true
-    arguments: ['@container.namespaces', '@cache.discovery', '@module_handler']
+    arguments: ['@container.namespaces', '@cache.discovery', '@module_handler', '@event_dispatcher']
   module_handler:
     class: Drupal\Core\Extension\ModuleHandler
     arguments: ['%container.modules%', '@cache.bootstrap']
@@ -293,7 +293,7 @@ services:
     arguments: ['@config.factory', '@module_handler', '@state', '@info_parser', '@logger.channel.default', '@asset.css.collection_optimizer', '@config.installer', '@config.manager', '@router.builder']
   entity.manager:
     class: Drupal\Core\Entity\EntityManager
-    arguments: ['@container.namespaces', '@module_handler', '@cache.discovery', '@language_manager', '@string_translation', '@class_resolver', '@typed_data_manager', '@entity.definitions.installed']
+    arguments: ['@container.namespaces', '@module_handler', '@event_dispatcher', '@cache.discovery', '@language_manager', '@string_translation', '@class_resolver', '@typed_data_manager', '@entity.definitions.installed']
     parent: container.trait
     tags:
       - { name: plugin_manager_cache_clear }
@@ -313,19 +313,19 @@ services:
     parent: default_plugin_manager
   plugin.manager.field.field_type:
     class: Drupal\Core\Field\FieldTypePluginManager
-    arguments: ['@container.namespaces', '@cache.discovery', '@module_handler']
+    parent: default_plugin_manager
   plugin.manager.field.widget:
     class: Drupal\Core\Field\WidgetPluginManager
-    arguments: ['@container.namespaces', '@cache.discovery', '@module_handler', '@plugin.manager.field.field_type']
+    arguments: ['@container.namespaces', '@cache.discovery', '@module_handler', '@event_dispatcher', '@plugin.manager.field.field_type']
   plugin.manager.field.formatter:
     class: Drupal\Core\Field\FormatterPluginManager
-    arguments: ['@container.namespaces', '@cache.discovery', '@module_handler', '@plugin.manager.field.field_type']
+    arguments: ['@container.namespaces', '@cache.discovery', '@module_handler', '@event_dispatcher', '@plugin.manager.field.field_type']
   plugin.manager.archiver:
     class: Drupal\Core\Archiver\ArchiverManager
     parent: default_plugin_manager
   plugin.manager.action:
     class: Drupal\Core\Action\ActionManager
-    arguments: ['@container.namespaces', '@cache.discovery', '@module_handler']
+    parent: default_plugin_manager
   plugin.manager.menu.link:
     class: Drupal\Core\Menu\MenuLinkManager
     arguments: ['@menu.tree_storage', '@menu_link.static.overrides', '@module_handler']
@@ -343,13 +343,13 @@ services:
     arguments: ['@menu.link_tree', '@entity.manager', '@string_translation']
   plugin.manager.menu.local_action:
     class: Drupal\Core\Menu\LocalActionManager
-    arguments: ['@controller_resolver', '@request_stack', '@router.route_provider', '@module_handler', '@cache.discovery', '@language_manager', '@access_manager', '@current_user']
+    arguments: ['@controller_resolver', '@request_stack', '@router.route_provider', '@module_handler', '@event_dispatcher', '@cache.discovery', '@language_manager', '@access_manager', '@current_user']
   plugin.manager.menu.local_task:
     class: Drupal\Core\Menu\LocalTaskManager
-    arguments: ['@controller_resolver', '@request_stack', '@router.route_provider', '@router.builder', '@module_handler', '@cache.discovery', '@language_manager', '@access_manager', '@current_user']
+    arguments: ['@controller_resolver', '@request_stack', '@router.route_provider', '@router.builder', '@module_handler', '@event_dispatcher', '@cache.discovery', '@language_manager', '@access_manager', '@current_user']
   plugin.manager.menu.contextual_link:
     class: Drupal\Core\Menu\ContextualLinkManager
-    arguments: ['@controller_resolver', '@module_handler', '@cache.discovery', '@language_manager', '@access_manager', '@current_user', '@request_stack']
+    arguments: ['@controller_resolver', '@module_handler', '@event_dispatcher', '@cache.discovery', '@language_manager', '@access_manager', '@current_user', '@request_stack']
   plugin.manager.display_variant:
     class: Drupal\Core\Display\VariantManager
     parent: default_plugin_manager
@@ -380,7 +380,7 @@ services:
      class: Drupal\Core\Routing\CurrentRouteMatch
      arguments: ['@request_stack']
   event_dispatcher:
-    class: Symfony\Component\EventDispatcher\ContainerAwareEventDispatcher
+    class: Drupal\Core\EventDispatcher\ContainerAwareEventDispatcher
     arguments: ['@service_container']
   controller_resolver:
     class: Drupal\Core\Controller\ControllerResolver
@@ -849,7 +849,7 @@ services:
       - { name: backend_overridable }
   plugin.manager.mail:
     class: Drupal\Core\Mail\MailManager
-    arguments: ['@container.namespaces', '@cache.discovery', '@module_handler', '@config.factory', '@logger.factory', '@string_translation']
+    arguments: ['@container.namespaces', '@cache.discovery', '@module_handler', '@event_dispatcher', '@config.factory', '@logger.factory', '@string_translation']
   plugin.manager.condition:
     class: Drupal\Core\Condition\ConditionManager
     parent: default_plugin_manager
diff --git a/core/lib/Drupal/Core/Action/ActionManager.php b/core/lib/Drupal/Core/Action/ActionManager.php
index 1baf427..1a9ab2a 100644
--- a/core/lib/Drupal/Core/Action/ActionManager.php
+++ b/core/lib/Drupal/Core/Action/ActionManager.php
@@ -10,6 +10,7 @@
 use Drupal\Core\Cache\CacheBackendInterface;
 use Drupal\Core\Extension\ModuleHandlerInterface;
 use Drupal\Core\Plugin\DefaultPluginManager;
+use Symfony\Component\EventDispatcher\EventDispatcherInterface;
 
 /**
  * Provides an Action plugin manager.
@@ -31,9 +32,11 @@ class ActionManager extends DefaultPluginManager {
    *   Cache backend instance to use.
    * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
    *   The module handler to invoke the alter hook with.
+   * @param \Symfony\Component\EventDispatcher\EventDispatcherInterface $event_dispatcher
+   *   The event dispatcher.
    */
-  public function __construct(\Traversable $namespaces, CacheBackendInterface $cache_backend, ModuleHandlerInterface $module_handler) {
-    parent::__construct('Plugin/Action', $namespaces, $module_handler, 'Drupal\Core\Action\ActionInterface', 'Drupal\Core\Annotation\Action');
+  public function __construct(\Traversable $namespaces, CacheBackendInterface $cache_backend, ModuleHandlerInterface $module_handler, EventDispatcherInterface $event_dispatcher) {
+    parent::__construct('Plugin/Action', $namespaces, $module_handler, $event_dispatcher, 'Drupal\Core\Action\ActionInterface', 'Drupal\Core\Annotation\Action');
     $this->alterInfo('action_info');
     $this->setCacheBackend($cache_backend, 'action_info');
   }
diff --git a/core/lib/Drupal/Core/Archiver/ArchiverManager.php b/core/lib/Drupal/Core/Archiver/ArchiverManager.php
index b8ac88c..1015436 100644
--- a/core/lib/Drupal/Core/Archiver/ArchiverManager.php
+++ b/core/lib/Drupal/Core/Archiver/ArchiverManager.php
@@ -11,6 +11,7 @@
 use Drupal\Core\Cache\CacheBackendInterface;
 use Drupal\Core\Extension\ModuleHandlerInterface;
 use Drupal\Core\Plugin\DefaultPluginManager;
+use Symfony\Component\EventDispatcher\EventDispatcherInterface;
 
 /**
  * Provides an Archiver plugin manager.
@@ -31,9 +32,11 @@ class ArchiverManager extends DefaultPluginManager {
    *   Cache backend instance to use.
    * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
    *   The module handler to invoke the alter hook with.
+   * @param \Symfony\Component\EventDispatcher\EventDispatcherInterface $event_dispatcher
+   *   The event dispatcher.
    */
-  public function __construct(\Traversable $namespaces, CacheBackendInterface $cache_backend, ModuleHandlerInterface $module_handler) {
-    parent::__construct('Plugin/Archiver', $namespaces, $module_handler, 'Drupal\Core\Archiver\ArchiverInterface', 'Drupal\Core\Archiver\Annotation\Archiver');
+  public function __construct(\Traversable $namespaces, CacheBackendInterface $cache_backend, ModuleHandlerInterface $module_handler, EventDispatcherInterface $event_dispatcher) {
+    parent::__construct('Plugin/Archiver', $namespaces, $module_handler, $event_dispatcher, 'Drupal\Core\Archiver\ArchiverInterface', 'Drupal\Core\Archiver\Annotation\Archiver');
     $this->alterInfo('archiver_info');
     $this->setCacheBackend($cache_backend, 'archiver_info_plugins');
   }
diff --git a/core/lib/Drupal/Core/Block/BlockManager.php b/core/lib/Drupal/Core/Block/BlockManager.php
index 8cde728..3252c42 100644
--- a/core/lib/Drupal/Core/Block/BlockManager.php
+++ b/core/lib/Drupal/Core/Block/BlockManager.php
@@ -12,6 +12,7 @@
 use Drupal\Core\Plugin\Context\ContextAwarePluginManagerTrait;
 use Drupal\Core\Plugin\DefaultPluginManager;
 use Drupal\Core\StringTranslation\StringTranslationTrait;
+use Symfony\Component\EventDispatcher\EventDispatcherInterface;
 
 /**
  * Manages discovery and instantiation of block plugins.
@@ -42,9 +43,11 @@ class BlockManager extends DefaultPluginManager implements BlockManagerInterface
    *   Cache backend instance to use.
    * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
    *   The module handler to invoke the alter hook with.
+   * @param \Symfony\Component\EventDispatcher\EventDispatcherInterface $event_dispatcher
+   *   The event dispatcher.
    */
-  public function __construct(\Traversable $namespaces, CacheBackendInterface $cache_backend, ModuleHandlerInterface $module_handler) {
-    parent::__construct('Plugin/Block', $namespaces, $module_handler, 'Drupal\Core\Block\BlockPluginInterface', 'Drupal\Core\Block\Annotation\Block');
+  public function __construct(\Traversable $namespaces, CacheBackendInterface $cache_backend, ModuleHandlerInterface $module_handler, EventDispatcherInterface $event_dispatcher) {
+    parent::__construct('Plugin/Block', $namespaces, $module_handler, $event_dispatcher, 'Drupal\Core\Block\BlockPluginInterface', 'Drupal\Core\Block\Annotation\Block');
 
     $this->alterInfo('block');
     $this->setCacheBackend($cache_backend, 'block_plugins');
@@ -111,4 +114,12 @@ public function getSortedDefinitions() {
     return $definitions;
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public function removePlugin($plugin_id, array $conditions = array()) {
+    parent::removePlugin($plugin_id, $conditions);
+    $this->clearCachedDefinitions();
+  }
+
 }
diff --git a/core/lib/Drupal/Core/Condition/ConditionManager.php b/core/lib/Drupal/Core/Condition/ConditionManager.php
index c1e309a..3662246 100644
--- a/core/lib/Drupal/Core/Condition/ConditionManager.php
+++ b/core/lib/Drupal/Core/Condition/ConditionManager.php
@@ -13,6 +13,7 @@
 use Drupal\Core\Extension\ModuleHandlerInterface;
 use Drupal\Core\Plugin\Context\ContextAwarePluginManagerTrait;
 use Drupal\Core\Plugin\DefaultPluginManager;
+use Symfony\Component\EventDispatcher\EventDispatcherInterface;
 
 /**
  * A plugin manager for condition plugins.
@@ -37,12 +38,14 @@ class ConditionManager extends DefaultPluginManager implements ExecutableManager
    *   Cache backend instance to use.
    * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
    *   The module handler to invoke the alter hook with.
+   * @param \Symfony\Component\EventDispatcher\EventDispatcherInterface $event_dispatcher
+   *   The event dispatcher.
    */
-  public function __construct(\Traversable $namespaces, CacheBackendInterface $cache_backend, ModuleHandlerInterface $module_handler) {
+  public function __construct(\Traversable $namespaces, CacheBackendInterface $cache_backend, ModuleHandlerInterface $module_handler, EventDispatcherInterface $event_dispatcher) {
     $this->alterInfo('condition_info');
     $this->setCacheBackend($cache_backend, 'condition_plugins');
 
-    parent::__construct('Plugin/Condition', $namespaces, $module_handler, 'Drupal\Core\Condition\ConditionInterface', 'Drupal\Core\Condition\Annotation\Condition');
+    parent::__construct('Plugin/Condition', $namespaces, $module_handler, $event_dispatcher, 'Drupal\Core\Condition\ConditionInterface', 'Drupal\Core\Condition\Annotation\Condition');
   }
 
   /**
diff --git a/core/lib/Drupal/Core/Config/TypedConfigManager.php b/core/lib/Drupal/Core/Config/TypedConfigManager.php
index d775cc2..848d92b 100644
--- a/core/lib/Drupal/Core/Config/TypedConfigManager.php
+++ b/core/lib/Drupal/Core/Config/TypedConfigManager.php
@@ -12,6 +12,7 @@
 use Drupal\Core\Config\Schema\ConfigSchemaDiscovery;
 use Drupal\Core\Extension\ModuleHandlerInterface;
 use Drupal\Core\TypedData\TypedDataManager;
+use Symfony\Component\EventDispatcher\EventDispatcherInterface;
 
 /**
  * Manages config type plugins.
@@ -49,13 +50,14 @@ class TypedConfigManager extends TypedDataManager implements TypedConfigManagerI
    * @param \Drupal\Core\Cache\CacheBackendInterface $cache
    *   The cache backend to use for caching the definitions.
    */
-  public function __construct(StorageInterface $configStorage, StorageInterface $schemaStorage, CacheBackendInterface $cache, ModuleHandlerInterface $module_handler) {
+  public function __construct(StorageInterface $configStorage, StorageInterface $schemaStorage, CacheBackendInterface $cache, ModuleHandlerInterface $module_handler, EventDispatcherInterface $event_dispatcher) {
     $this->configStorage = $configStorage;
     $this->schemaStorage = $schemaStorage;
     $this->setCacheBackend($cache, 'typed_config_definitions');
     $this->discovery = new ConfigSchemaDiscovery($schemaStorage);
     $this->alterInfo('config_schema_info');
     $this->moduleHandler = $module_handler;
+    $this->eventDispatcher = $event_dispatcher;
   }
 
   /**
diff --git a/core/lib/Drupal/Core/Display/VariantManager.php b/core/lib/Drupal/Core/Display/VariantManager.php
index ef1f50f..7986c57 100644
--- a/core/lib/Drupal/Core/Display/VariantManager.php
+++ b/core/lib/Drupal/Core/Display/VariantManager.php
@@ -10,6 +10,7 @@
 use Drupal\Core\Cache\CacheBackendInterface;
 use Drupal\Core\Extension\ModuleHandlerInterface;
 use Drupal\Core\Plugin\DefaultPluginManager;
+use Symfony\Component\EventDispatcher\EventDispatcherInterface;
 
 /**
  * Manages discovery of display variant plugins.
@@ -31,9 +32,11 @@ class VariantManager extends DefaultPluginManager {
    *   Cache backend instance to use.
    * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
    *   The module handler to invoke the alter hook with.
+   * @param \Symfony\Component\EventDispatcher\EventDispatcherInterface $event_dispatcher
+   *   The event dispatcher.
    */
-  public function __construct(\Traversable $namespaces, CacheBackendInterface $cache_backend, ModuleHandlerInterface $module_handler) {
-    parent::__construct('Plugin/DisplayVariant', $namespaces, $module_handler, 'Drupal\Core\Display\VariantInterface', 'Drupal\Core\Display\Annotation\DisplayVariant');
+  public function __construct(\Traversable $namespaces, CacheBackendInterface $cache_backend, ModuleHandlerInterface $module_handler, EventDispatcherInterface $event_dispatcher) {
+    parent::__construct('Plugin/DisplayVariant', $namespaces, $module_handler, $event_dispatcher, 'Drupal\Core\Display\VariantInterface', 'Drupal\Core\Display\Annotation\DisplayVariant');
 
     $this->setCacheBackend($cache_backend, 'variant_plugins');
     $this->alterInfo('display_variant_plugin');
diff --git a/core/lib/Drupal/Core/Entity/EntityManager.php b/core/lib/Drupal/Core/Entity/EntityManager.php
index 94fe169..6d8ab05 100644
--- a/core/lib/Drupal/Core/Entity/EntityManager.php
+++ b/core/lib/Drupal/Core/Entity/EntityManager.php
@@ -29,6 +29,7 @@
 use Drupal\Core\TypedData\TypedDataManager;
 use Symfony\Component\DependencyInjection\ContainerAwareInterface;
 use Symfony\Component\DependencyInjection\ContainerAwareTrait;
+use Symfony\Component\EventDispatcher\EventDispatcherInterface;
 
 /**
  * Manages entity type plugin definitions.
@@ -171,6 +172,8 @@ class EntityManager extends DefaultPluginManager implements EntityManagerInterfa
    *   keyed by the corresponding namespace to look for plugin implementations,
    * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
    *   The module handler.
+   * @param \Symfony\Component\EventDispatcher\EventDispatcherInterface $event_dispatcher
+   *   The event dispatcher.
    * @param \Drupal\Core\Cache\CacheBackendInterface $cache
    *   The cache backend to use.
    * @param \Drupal\Core\Language\LanguageManagerInterface $language_manager
@@ -184,8 +187,8 @@ class EntityManager extends DefaultPluginManager implements EntityManagerInterfa
    * @param \Drupal\Core\KeyValueStore\KeyValueStoreInterface $installed_definitions
    *   The keyvalue collection for tracking installed definitions.
    */
-  public function __construct(\Traversable $namespaces, ModuleHandlerInterface $module_handler, CacheBackendInterface $cache, LanguageManagerInterface $language_manager, TranslationInterface $translation_manager, ClassResolverInterface $class_resolver, TypedDataManager $typed_data_manager, KeyValueStoreInterface $installed_definitions) {
-    parent::__construct('Entity', $namespaces, $module_handler, 'Drupal\Core\Entity\EntityInterface', 'Drupal\Core\Entity\Annotation\EntityType');
+  public function __construct(\Traversable $namespaces, ModuleHandlerInterface $module_handler, EventDispatcherInterface $event_dispatcher, CacheBackendInterface $cache, LanguageManagerInterface $language_manager, TranslationInterface $translation_manager, ClassResolverInterface $class_resolver, TypedDataManager $typed_data_manager, KeyValueStoreInterface $installed_definitions) {
+    parent::__construct('Entity', $namespaces, $module_handler, $event_dispatcher, 'Drupal\Core\Entity\EntityInterface', 'Drupal\Core\Entity\Annotation\EntityType');
 
     $this->setCacheBackend($cache, 'entity_type', array('entity_types'));
     $this->alterInfo('entity_type');
diff --git a/core/lib/Drupal/Core/EventDispatcher/ContainerAwareEventDispatcher.php b/core/lib/Drupal/Core/EventDispatcher/ContainerAwareEventDispatcher.php
new file mode 100644
index 0000000..42e7c6d
--- /dev/null
+++ b/core/lib/Drupal/Core/EventDispatcher/ContainerAwareEventDispatcher.php
@@ -0,0 +1,21 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\EventDispatcher\ContainerAwareEventDispatcher.
+ */
+
+namespace Drupal\Core\EventDispatcher;
+
+use Drupal\Core\DependencyInjection\DependencySerializationTrait;
+use Symfony\Component\EventDispatcher\ContainerAwareEventDispatcher as BaseContainerAwareEventDispatcher;
+
+/**
+ * Extends the base event dispatcher to be serializable.
+ */
+class ContainerAwareEventDispatcher extends BaseContainerAwareEventDispatcher {
+
+  use DependencySerializationTrait;
+
+}
+
diff --git a/core/lib/Drupal/Core/Field/FieldTypePluginManager.php b/core/lib/Drupal/Core/Field/FieldTypePluginManager.php
index e355985..4c1d103 100644
--- a/core/lib/Drupal/Core/Field/FieldTypePluginManager.php
+++ b/core/lib/Drupal/Core/Field/FieldTypePluginManager.php
@@ -11,6 +11,7 @@
 use Drupal\Core\Cache\CacheBackendInterface;
 use Drupal\Core\Extension\ModuleHandlerInterface;
 use Drupal\Core\Plugin\DefaultPluginManager;
+use Symfony\Component\EventDispatcher\EventDispatcherInterface;
 
 /**
  * Plugin manager for 'field type' plugins.
@@ -29,9 +30,11 @@ class FieldTypePluginManager extends DefaultPluginManager implements FieldTypePl
    *   Cache backend instance to use.
    * @param \Drupal\Core\Extension\ModuleHandlerInterface
    *   The module handler.
+   * @param \Symfony\Component\EventDispatcher\EventDispatcherInterface $event_dispatcher
+   *   The event dispatcher.
    */
-  public function __construct(\Traversable $namespaces, CacheBackendInterface $cache_backend, ModuleHandlerInterface $module_handler) {
-    parent::__construct('Plugin/Field/FieldType', $namespaces, $module_handler, 'Drupal\Core\Field\FieldItemInterface', 'Drupal\Core\Field\Annotation\FieldType');
+  public function __construct(\Traversable $namespaces, CacheBackendInterface $cache_backend, ModuleHandlerInterface $module_handler, EventDispatcherInterface $event_dispatcher) {
+    parent::__construct('Plugin/Field/FieldType', $namespaces, $module_handler, $event_dispatcher, 'Drupal\Core\Field\FieldItemInterface', 'Drupal\Core\Field\Annotation\FieldType');
     $this->alterInfo('field_info');
     $this->setCacheBackend($cache_backend, 'field_types_plugins');
   }
diff --git a/core/lib/Drupal/Core/Field/FormatterPluginManager.php b/core/lib/Drupal/Core/Field/FormatterPluginManager.php
index b7b297b..234c361 100644
--- a/core/lib/Drupal/Core/Field/FormatterPluginManager.php
+++ b/core/lib/Drupal/Core/Field/FormatterPluginManager.php
@@ -11,6 +11,7 @@
 use Drupal\Core\Cache\CacheBackendInterface;
 use Drupal\Core\Extension\ModuleHandlerInterface;
 use Drupal\Core\Plugin\DefaultPluginManager;
+use Symfony\Component\EventDispatcher\EventDispatcherInterface;
 
 /**
  * Plugin type manager for field formatters.
@@ -46,8 +47,8 @@ class FormatterPluginManager extends DefaultPluginManager {
    * @param \Drupal\Core\Field\FieldTypePluginManagerInterface $field_type_manager
    *   The 'field type' plugin manager.
    */
-  public function __construct(\Traversable $namespaces, CacheBackendInterface $cache_backend, ModuleHandlerInterface $module_handler, FieldTypePluginManagerInterface $field_type_manager) {
-    parent::__construct('Plugin/Field/FieldFormatter', $namespaces, $module_handler, 'Drupal\Core\Field\FormatterInterface', 'Drupal\Core\Field\Annotation\FieldFormatter');
+  public function __construct(\Traversable $namespaces, CacheBackendInterface $cache_backend, ModuleHandlerInterface $module_handler, EventDispatcherInterface $event_dispatcher, FieldTypePluginManagerInterface $field_type_manager) {
+    parent::__construct('Plugin/Field/FieldFormatter', $namespaces, $module_handler, $event_dispatcher, 'Drupal\Core\Field\FormatterInterface', 'Drupal\Core\Field\Annotation\FieldFormatter');
 
     $this->setCacheBackend($cache_backend, 'field_formatter_types_plugins');
     $this->alterInfo('field_formatter_info');
diff --git a/core/lib/Drupal/Core/Field/WidgetPluginManager.php b/core/lib/Drupal/Core/Field/WidgetPluginManager.php
index 8aa4434..41ae461 100644
--- a/core/lib/Drupal/Core/Field/WidgetPluginManager.php
+++ b/core/lib/Drupal/Core/Field/WidgetPluginManager.php
@@ -11,6 +11,7 @@
 use Drupal\Core\Cache\CacheBackendInterface;
 use Drupal\Core\Extension\ModuleHandlerInterface;
 use Drupal\Core\Plugin\DefaultPluginManager;
+use Symfony\Component\EventDispatcher\EventDispatcherInterface;
 
 /**
  * Plugin type manager for field widgets.
@@ -43,11 +44,13 @@ class WidgetPluginManager extends DefaultPluginManager {
    *   Cache backend instance to use.
    * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
    *   The module handler.
+   * @param \Symfony\Component\EventDispatcher\EventDispatcherInterface $event_dispatcher
+   *   The event dispatcher.
    * @param \Drupal\Core\Field\FieldTypePluginManagerInterface $field_type_manager
    *   The 'field type' plugin manager.
    */
-  public function __construct(\Traversable $namespaces, CacheBackendInterface $cache_backend, ModuleHandlerInterface $module_handler, FieldTypePluginManagerInterface $field_type_manager) {
-    parent::__construct('Plugin/Field/FieldWidget', $namespaces, $module_handler, 'Drupal\Core\Field\WidgetInterface', 'Drupal\Core\Field\Annotation\FieldWidget');
+  public function __construct(\Traversable $namespaces, CacheBackendInterface $cache_backend, ModuleHandlerInterface $module_handler, EventDispatcherInterface $event_dispatcher, FieldTypePluginManagerInterface $field_type_manager) {
+    parent::__construct('Plugin/Field/FieldWidget', $namespaces, $module_handler, $event_dispatcher, 'Drupal\Core\Field\WidgetInterface', 'Drupal\Core\Field\Annotation\FieldWidget');
 
     $this->setCacheBackend($cache_backend, 'field_widget_types_plugins');
     $this->alterInfo('field_widget_info');
diff --git a/core/lib/Drupal/Core/ImageToolkit/ImageToolkitManager.php b/core/lib/Drupal/Core/ImageToolkit/ImageToolkitManager.php
index 2857bbd..6b70079 100644
--- a/core/lib/Drupal/Core/ImageToolkit/ImageToolkitManager.php
+++ b/core/lib/Drupal/Core/ImageToolkit/ImageToolkitManager.php
@@ -11,6 +11,7 @@
 use Drupal\Core\Config\ConfigFactoryInterface;
 use Drupal\Core\Extension\ModuleHandlerInterface;
 use Drupal\Core\Plugin\DefaultPluginManager;
+use Symfony\Component\EventDispatcher\EventDispatcherInterface;
 
 /**
  * Manages image toolkit plugins.
@@ -39,11 +40,13 @@ class ImageToolkitManager extends DefaultPluginManager {
    *   Cache backend instance to use.
    * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
    *   The module handler.
+   * @param \Symfony\Component\EventDispatcher\EventDispatcherInterface $event_dispatcher
+   *   The event dispatcher.
    * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
    *   The config factory.
    */
-  public function __construct(\Traversable $namespaces, CacheBackendInterface $cache_backend, ModuleHandlerInterface $module_handler, ConfigFactoryInterface $config_factory) {
-    parent::__construct('Plugin/ImageToolkit', $namespaces, $module_handler, 'Drupal\Core\ImageToolkit\ImageToolkitInterface', 'Drupal\Core\ImageToolkit\Annotation\ImageToolkit');
+  public function __construct(\Traversable $namespaces, CacheBackendInterface $cache_backend, ModuleHandlerInterface $module_handler, EventDispatcherInterface $event_dispatcher, ConfigFactoryInterface $config_factory) {
+    parent::__construct('Plugin/ImageToolkit', $namespaces, $module_handler, $event_dispatcher, 'Drupal\Core\ImageToolkit\ImageToolkitInterface', 'Drupal\Core\ImageToolkit\Annotation\ImageToolkit');
 
     $this->setCacheBackend($cache_backend, 'image_toolkit_plugins');
     $this->configFactory = $config_factory;
diff --git a/core/lib/Drupal/Core/ImageToolkit/ImageToolkitOperationManager.php b/core/lib/Drupal/Core/ImageToolkit/ImageToolkitOperationManager.php
index dc4abaa..912b999 100644
--- a/core/lib/Drupal/Core/ImageToolkit/ImageToolkitOperationManager.php
+++ b/core/lib/Drupal/Core/ImageToolkit/ImageToolkitOperationManager.php
@@ -14,6 +14,7 @@
 use Drupal\Component\Plugin\Factory\DefaultFactory;
 use Drupal\Component\Utility\String;
 use Psr\Log\LoggerInterface;
+use Symfony\Component\EventDispatcher\EventDispatcherInterface;
 
 /**
  * Manages toolkit operation plugins.
@@ -42,11 +43,13 @@ class ImageToolkitOperationManager extends DefaultPluginManager implements Image
    *   Cache backend instance to use.
    * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
    *   The module handler to invoke the alter hook with.
+   * @param \Symfony\Component\EventDispatcher\EventDispatcherInterface $event_dispatcher
+   *   The event dispatcher.
    * @param \Psr\Log\LoggerInterface $logger
    *   A logger instance.
    */
-  public function __construct(\Traversable $namespaces, CacheBackendInterface $cache_backend, ModuleHandlerInterface $module_handler, LoggerInterface $logger) {
-    parent::__construct('Plugin/ImageToolkit/Operation', $namespaces, $module_handler, 'Drupal\Core\ImageToolkit\ImageToolkitOperationInterface', 'Drupal\Core\ImageToolkit\Annotation\ImageToolkitOperation');
+  public function __construct(\Traversable $namespaces, CacheBackendInterface $cache_backend, ModuleHandlerInterface $module_handler, EventDispatcherInterface $event_dispatcher, LoggerInterface $logger) {
+    parent::__construct('Plugin/ImageToolkit/Operation', $namespaces, $module_handler, $event_dispatcher, 'Drupal\Core\ImageToolkit\ImageToolkitOperationInterface', 'Drupal\Core\ImageToolkit\Annotation\ImageToolkitOperation');
 
     $this->alterInfo('image_toolkit_operation');
     $this->setCacheBackend($cache_backend, 'image_toolkit_operation_plugins');
diff --git a/core/lib/Drupal/Core/Mail/MailManager.php b/core/lib/Drupal/Core/Mail/MailManager.php
index decbeed..b7f9016 100644
--- a/core/lib/Drupal/Core/Mail/MailManager.php
+++ b/core/lib/Drupal/Core/Mail/MailManager.php
@@ -14,6 +14,7 @@
 use Drupal\Core\Config\ConfigFactoryInterface;
 use Drupal\Core\StringTranslation\StringTranslationTrait;
 use Drupal\Core\StringTranslation\TranslationInterface;
+use Symfony\Component\EventDispatcher\EventDispatcherInterface;
 
 /**
  * Provides a Mail plugin manager.
@@ -57,6 +58,8 @@ class MailManager extends DefaultPluginManager implements MailManagerInterface {
    *   Cache backend instance to use.
    * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
    *   The module handler to invoke the alter hook with.
+   * @param \Symfony\Component\EventDispatcher\EventDispatcherInterface $event_dispatcher
+   *   The event dispatcher.
    * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
    *   The configuration factory.
    * @param \Drupal\Core\Logger\LoggerChannelFactoryInterface $logger_factory
@@ -64,8 +67,8 @@ class MailManager extends DefaultPluginManager implements MailManagerInterface {
    * @param \Drupal\Core\StringTranslation\TranslationInterface $string_translation
    *   The string translation service.
    */
-  public function __construct(\Traversable $namespaces, CacheBackendInterface $cache_backend, ModuleHandlerInterface $module_handler, ConfigFactoryInterface $config_factory, LoggerChannelFactoryInterface $logger_factory, TranslationInterface $string_translation) {
-    parent::__construct('Plugin/Mail', $namespaces, $module_handler, 'Drupal\Core\Mail\MailInterface', 'Drupal\Core\Annotation\Mail');
+  public function __construct(\Traversable $namespaces, CacheBackendInterface $cache_backend, ModuleHandlerInterface $module_handler, EventDispatcherInterface $event_dispatcher, ConfigFactoryInterface $config_factory, LoggerChannelFactoryInterface $logger_factory, TranslationInterface $string_translation) {
+    parent::__construct('Plugin/Mail', $namespaces, $module_handler, $event_dispatcher, 'Drupal\Core\Mail\MailInterface', 'Drupal\Core\Annotation\Mail');
     $this->alterInfo('mail_backend_info');
     $this->setCacheBackend($cache_backend, 'mail_backend_plugins');
     $this->configFactory = $config_factory;
diff --git a/core/lib/Drupal/Core/Menu/ContextualLinkManager.php b/core/lib/Drupal/Core/Menu/ContextualLinkManager.php
index 140a69a..96a6cea 100644
--- a/core/lib/Drupal/Core/Menu/ContextualLinkManager.php
+++ b/core/lib/Drupal/Core/Menu/ContextualLinkManager.php
@@ -18,6 +18,7 @@
 use Drupal\Core\Plugin\Discovery\YamlDiscovery;
 use Drupal\Core\Plugin\Factory\ContainerFactory;
 use Drupal\Core\Session\AccountInterface;
+use Symfony\Component\EventDispatcher\EventDispatcherInterface;
 use Symfony\Component\HttpFoundation\RequestStack;
 
 /**
@@ -91,6 +92,8 @@ class ContextualLinkManager extends DefaultPluginManager implements ContextualLi
    *   The controller resolver.
    * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
    *   The module handler.
+   * @param \Symfony\Component\EventDispatcher\EventDispatcherInterface $event_dispatcher
+   *   The event dispatcher.
    * @param \Drupal\Core\Cache\CacheBackendInterface $cache_backend
    *   The cache backend.
    * @param \Drupal\Core\Language\LanguageManagerInterface $language_manager
@@ -102,7 +105,7 @@ class ContextualLinkManager extends DefaultPluginManager implements ContextualLi
    * @param \Symfony\Component\HttpFoundation\RequestStack $request_stack
    *   The request stack.
    */
-  public function __construct(ControllerResolverInterface $controller_resolver, ModuleHandlerInterface $module_handler, CacheBackendInterface $cache_backend, LanguageManagerInterface $language_manager, AccessManagerInterface $access_manager, AccountInterface $account, RequestStack $request_stack) {
+  public function __construct(ControllerResolverInterface $controller_resolver, ModuleHandlerInterface $module_handler, EventDispatcherInterface $event_dispatcher, CacheBackendInterface $cache_backend, LanguageManagerInterface $language_manager, AccessManagerInterface $access_manager, AccountInterface $account, RequestStack $request_stack) {
     $this->discovery = new YamlDiscovery('links.contextual', $module_handler->getModuleDirectories());
     $this->discovery = new ContainerDerivativeDiscoveryDecorator($this->discovery);
     $this->factory = new ContainerFactory($this, '\Drupal\Core\Menu\ContextualLinkInterface');
@@ -111,6 +114,7 @@ public function __construct(ControllerResolverInterface $controller_resolver, Mo
     $this->accessManager = $access_manager;
     $this->account = $account;
     $this->moduleHandler = $module_handler;
+    $this->eventDispatcher = $event_dispatcher;
     $this->requestStack = $request_stack;
     $this->alterInfo('contextual_links_plugins');
     $this->setCacheBackend($cache_backend, 'contextual_links_plugins:' . $language_manager->getCurrentLanguage()->getId(), array('contextual_links_plugins'));
diff --git a/core/lib/Drupal/Core/Menu/LocalActionManager.php b/core/lib/Drupal/Core/Menu/LocalActionManager.php
index 2e4eb92..1d71306 100644
--- a/core/lib/Drupal/Core/Menu/LocalActionManager.php
+++ b/core/lib/Drupal/Core/Menu/LocalActionManager.php
@@ -16,6 +16,7 @@
 use Drupal\Core\Plugin\Discovery\YamlDiscovery;
 use Drupal\Core\Plugin\Factory\ContainerFactory;
 use Drupal\Core\Routing\RouteProviderInterface;
+use Symfony\Component\EventDispatcher\EventDispatcherInterface;
 use Symfony\Component\HttpFoundation\RequestStack;
 use Symfony\Component\HttpKernel\Controller\ControllerResolverInterface;
 use Drupal\Core\Session\AccountInterface;
@@ -102,6 +103,8 @@ class LocalActionManager extends DefaultPluginManager implements LocalActionMana
    *   The route provider.
    * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
    *   The module handler.
+   * @param \Symfony\Component\EventDispatcher\EventDispatcherInterface $event_dispatcher
+   *   The event dispatcher.
    * @param \Drupal\Core\Cache\CacheBackendInterface $cache_backend
    *   Cache backend instance to use.
    * @param \Drupal\Core\Language\LanguageManagerInterface $language_manager
@@ -111,7 +114,7 @@ class LocalActionManager extends DefaultPluginManager implements LocalActionMana
    * @param \Drupal\Core\Session\AccountInterface $account
    *   The current user.
    */
-  public function __construct(ControllerResolverInterface $controller_resolver, RequestStack $request_stack, RouteProviderInterface $route_provider, ModuleHandlerInterface $module_handler, CacheBackendInterface $cache_backend, LanguageManagerInterface $language_manager, AccessManagerInterface $access_manager, AccountInterface $account) {
+  public function __construct(ControllerResolverInterface $controller_resolver, RequestStack $request_stack, RouteProviderInterface $route_provider, ModuleHandlerInterface $module_handler, EventDispatcherInterface $event_dispatcher, CacheBackendInterface $cache_backend, LanguageManagerInterface $language_manager, AccessManagerInterface $access_manager, AccountInterface $account) {
     // Skip calling the parent constructor, since that assumes annotation-based
     // discovery.
     $this->discovery = new YamlDiscovery('links.action', $module_handler->getModuleDirectories());
@@ -122,6 +125,7 @@ public function __construct(ControllerResolverInterface $controller_resolver, Re
     $this->routeProvider = $route_provider;
     $this->accessManager = $access_manager;
     $this->moduleHandler = $module_handler;
+    $this->eventDispatcher = $event_dispatcher;
     $this->account = $account;
     $this->alterInfo('menu_local_actions');
     $this->setCacheBackend($cache_backend, 'local_action_plugins:' . $language_manager->getCurrentLanguage()->getId(), array('local_action'));
diff --git a/core/lib/Drupal/Core/Menu/LocalTaskManager.php b/core/lib/Drupal/Core/Menu/LocalTaskManager.php
index 4e1f675..8df3405 100644
--- a/core/lib/Drupal/Core/Menu/LocalTaskManager.php
+++ b/core/lib/Drupal/Core/Menu/LocalTaskManager.php
@@ -21,6 +21,7 @@
 use Drupal\Core\Routing\RouteBuilderInterface;
 use Drupal\Core\Routing\RouteProviderInterface;
 use Drupal\Core\Session\AccountInterface;
+use Symfony\Component\EventDispatcher\EventDispatcherInterface;
 use Symfony\Component\HttpFoundation\RequestStack;
 
 /**
@@ -114,6 +115,8 @@ class LocalTaskManager extends DefaultPluginManager implements LocalTaskManagerI
    *   The route builder.
    * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
    *   The module handler.
+   * @param \Symfony\Component\EventDispatcher\EventDispatcherInterface $event_dispatcher
+   *   The event dispatcher.
    * @param \Drupal\Core\Cache\CacheBackendInterface $cache
    *   The cache backend.
    * @param \Drupal\Core\Language\LanguageManagerInterface $language_manager
@@ -123,7 +126,7 @@ class LocalTaskManager extends DefaultPluginManager implements LocalTaskManagerI
    * @param \Drupal\Core\Session\AccountInterface $account
    *   The current user.
    */
-  public function __construct(ControllerResolverInterface $controller_resolver, RequestStack $request_stack, RouteProviderInterface $route_provider, RouteBuilderInterface $route_builder, ModuleHandlerInterface $module_handler, CacheBackendInterface $cache, LanguageManagerInterface $language_manager, AccessManagerInterface $access_manager, AccountInterface $account) {
+  public function __construct(ControllerResolverInterface $controller_resolver, RequestStack $request_stack, RouteProviderInterface $route_provider, RouteBuilderInterface $route_builder, ModuleHandlerInterface $module_handler, EventDispatcherInterface $event_dispatcher, CacheBackendInterface $cache, LanguageManagerInterface $language_manager, AccessManagerInterface $access_manager, AccountInterface $account) {
     $this->discovery = new YamlDiscovery('links.task', $module_handler->getModuleDirectories());
     $this->discovery = new ContainerDerivativeDiscoveryDecorator($this->discovery);
     $this->factory = new ContainerFactory($this, '\Drupal\Core\Menu\LocalTaskInterface');
@@ -134,6 +137,7 @@ public function __construct(ControllerResolverInterface $controller_resolver, Re
     $this->accessManager = $access_manager;
     $this->account = $account;
     $this->moduleHandler = $module_handler;
+    $this->eventDispatcher = $event_dispatcher;
     $this->alterInfo('local_tasks');
     $this->setCacheBackend($cache, 'local_task_plugins:' . $language_manager->getCurrentLanguage()->getId(), array('local_task'));
   }
diff --git a/core/lib/Drupal/Core/Plugin/DefaultPluginManager.php b/core/lib/Drupal/Core/Plugin/DefaultPluginManager.php
index 5828d33..2ba78a1 100644
--- a/core/lib/Drupal/Core/Plugin/DefaultPluginManager.php
+++ b/core/lib/Drupal/Core/Plugin/DefaultPluginManager.php
@@ -17,14 +17,16 @@
 use Drupal\Core\Cache\CacheBackendInterface;
 use Drupal\Core\Extension\ModuleHandlerInterface;
 use Drupal\Core\Plugin\Discovery\AnnotatedClassDiscovery;
+use Drupal\Core\Plugin\Event\PluginRemovalEvent;
 use Drupal\Core\Plugin\Factory\ContainerFactory;
+use Symfony\Component\EventDispatcher\EventDispatcherInterface;
 
 /**
  * Base class for plugin managers.
  *
  * @ingroup plugin_api
  */
-class DefaultPluginManager extends PluginManagerBase implements PluginManagerInterface, CachedDiscoveryInterface {
+class DefaultPluginManager extends PluginManagerBase implements CachedDiscoveryInterface, DefaultPluginManagerInterface {
 
   use DiscoveryCachedTrait;
 
@@ -72,6 +74,13 @@ class DefaultPluginManager extends PluginManagerBase implements PluginManagerInt
   protected $moduleHandler;
 
   /**
+   * The event dispatcher.
+   *
+   * @var \Symfony\Component\EventDispatcher\EventDispatcherInterface
+   */
+  protected $eventDispatcher;
+
+  /**
    * A set of defaults to be referenced by $this->processDefinition() if
    * additional processing of plugins is necessary or helpful for development
    * purposes.
@@ -90,39 +99,25 @@ class DefaultPluginManager extends PluginManagerBase implements PluginManagerInt
    *   keyed by the corresponding namespace to look for plugin implementations.
    * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
    *   The module handler.
+   * @param \Symfony\Component\EventDispatcher\EventDispatcherInterface $event_dispatcher
+   *   The event dispatcher.
    * @param string|null $plugin_interface
    *   (optional) The interface each plugin should implement.
    * @param string $plugin_definition_annotation_name
    *   (optional) The name of the annotation that contains the plugin definition.
    *   Defaults to 'Drupal\Component\Annotation\Plugin'.
    */
-  public function __construct($subdir, \Traversable $namespaces, ModuleHandlerInterface $module_handler, $plugin_interface = NULL, $plugin_definition_annotation_name = 'Drupal\Component\Annotation\Plugin') {
+  public function __construct($subdir, \Traversable $namespaces, ModuleHandlerInterface $module_handler, EventDispatcherInterface $event_dispatcher, $plugin_interface = NULL, $plugin_definition_annotation_name = 'Drupal\Component\Annotation\Plugin') {
     $this->subdir = $subdir;
     $this->discovery = new AnnotatedClassDiscovery($subdir, $namespaces, $plugin_definition_annotation_name);
     $this->discovery = new ContainerDerivativeDiscoveryDecorator($this->discovery);
     $this->factory = new ContainerFactory($this, $plugin_interface);
     $this->moduleHandler = $module_handler;
+    $this->eventDispatcher = $event_dispatcher;
   }
 
   /**
-   * Initialize the cache backend.
-   *
-   * Plugin definitions are cached using the provided cache backend. The
-   * interface language is added as a suffix to the cache key.
-   *
-   * @param \Drupal\Core\Cache\CacheBackendInterface $cache_backend
-   *   Cache backend instance to use.
-   * @param string $cache_key
-   *   Cache key prefix to use, the language code will be appended
-   *   automatically.
-   * @param array $cache_tags
-   *   (optional) When providing a list of cache tags, the cached plugin
-   *   definitions are tagged with the provided cache tags. These cache tags can
-   *   then be used to clear the corresponding cached plugin definitions. Note
-   *   that this should be used with care! For clearing all cached plugin
-   *   definitions of a plugin manager, call that plugin manager's
-   *   clearCachedDefinitions() method. Only use cache tags when cached plugin
-   *   definitions should be cleared along with other, related cache entries.
+   * {@inheritdoc}
    */
   public function setCacheBackend(CacheBackendInterface $cache_backend, $cache_key, array $cache_tags = array()) {
     Cache::validateTags($cache_tags);
@@ -167,6 +162,15 @@ public function clearCachedDefinitions() {
         $this->cacheBackend->delete($this->cacheKey);
       }
     }
+
+    if ($existing_definitions = $this->getCachedDefinitions()) {
+      $new_definitions = $this->findDefinitions();
+      $removed_plugin_ids = array_diff(array_keys($existing_definitions), array_keys($new_definitions));
+      foreach ($removed_plugin_ids as $removed_plugin_id) {
+        $this->removePlugin($removed_plugin_id);
+      }
+    }
+
     $this->definitions = NULL;
   }
 
@@ -242,4 +246,13 @@ protected function findDefinitions() {
     return $definitions;
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public function removePlugin($plugin_id, array $conditions = array()) {
+    // @todo Introduce a proper plugin type.
+    $plugin_type = isset($this->subdir) ? strtolower(str_replace('/', '_', $this->subdir)) : get_class($this);
+    $this->eventDispatcher->dispatch(PluginEvents::REMOVAL, new PluginRemovalEvent($plugin_type, $plugin_id, $conditions));
+  }
+
 }
diff --git a/core/lib/Drupal/Core/Plugin/DefaultPluginManagerInterface.php b/core/lib/Drupal/Core/Plugin/DefaultPluginManagerInterface.php
new file mode 100644
index 0000000..c2b0a1b
--- /dev/null
+++ b/core/lib/Drupal/Core/Plugin/DefaultPluginManagerInterface.php
@@ -0,0 +1,54 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\Plugin\DefaultPluginManagerInterface.
+ */
+
+namespace Drupal\Core\Plugin;
+
+use Drupal\Component\Plugin\PluginManagerInterface;
+use Drupal\Core\Cache\CacheBackendInterface;
+
+/**
+ * Extends the plugin manager interface with Drupal specific methods.
+ */
+interface DefaultPluginManagerInterface extends PluginManagerInterface {
+
+  /**
+   * Initialize the cache backend.
+   *
+   * Plugin definitions are cached using the provided cache backend. The
+   * interface language is added as a suffix to the cache key.
+   *
+   * @param \Drupal\Core\Cache\CacheBackendInterface $cache_backend
+   *   Cache backend instance to use.
+   * @param string $cache_key
+   *   Cache key prefix to use, the language code will be appended
+   *   automatically.
+   * @param array $cache_tags
+   *   (optional) When providing a list of cache tags, the cached plugin
+   *   definitions are tagged with the provided cache tags. These cache tags can
+   *   then be used to clear the corresponding cached plugin definitions. Note
+   *   that this should be used with care! For clearing all cached plugin
+   *   definitions of a plugin manager, call that plugin manager's
+   *   clearCachedDefinitions() method. Only use cache tags when cached plugin
+   *   definitions should be cleared along with other, related cache entries.
+   */
+  public function setCacheBackend(CacheBackendInterface $cache_backend, $cache_key, array $cache_tags = array());
+
+  /**
+   * Announces that the plugin with the specified ID disappears.
+   *
+   * A concrete example is that you want to remove each block configuration once
+   * a content block is removed.
+   *
+   * @param string $plugin_id
+   *   The ID of the plugin that is removed.
+   * @param array $conditions
+   *   (optional) An array of information that is passed on to the subscribers
+   *   to help them decide how to react on the plugin removal.
+   */
+  public function removePlugin($plugin_id, array $conditions = array());
+
+}
diff --git a/core/lib/Drupal/Core/Plugin/Event/PluginRemovalEvent.php b/core/lib/Drupal/Core/Plugin/Event/PluginRemovalEvent.php
new file mode 100644
index 0000000..628b117
--- /dev/null
+++ b/core/lib/Drupal/Core/Plugin/Event/PluginRemovalEvent.php
@@ -0,0 +1,86 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\Plugin\Event\PluginRemovalEvent.
+ */
+
+namespace Drupal\Core\Plugin\Event;
+
+use Symfony\Component\EventDispatcher\Event;
+
+/**
+ * Event that fires when a plugin is removed.
+ */
+class PluginRemovalEvent extends Event {
+
+  /**
+   * The plugin type.
+   *
+   * @var string
+   */
+  protected $pluginType;
+
+  /**
+   * The plugin ID.
+   *
+   * @var string
+   */
+  protected $pluginId;
+
+  /**
+   * An array of conditions.
+   *
+   * These are provided to help subscribers deciding how to act on the removal.
+   *
+   * @var array
+   */
+  protected $conditions;
+
+  /**
+   * Constructs a PluginRemovalEvent object.
+   *
+   * @param string $plugin_type
+   *   A unique string for each plugin type.
+   * @param string $plugin_id
+   *   The ID of the plugin that is being removed.
+   * @param array $conditions
+   *   An array of conditions intended to help subscribers to decide how to act
+   *   on the plugin removal.
+   */
+  public function __construct($plugin_type, $plugin_id, array $conditions = array()) {
+    $this->pluginType = $plugin_type;
+    $this->pluginId = $plugin_id;
+    $this->conditions = $conditions;
+  }
+
+  /**
+   * Returns the plugin removal conditions.
+   *
+   * @return array
+   *   An array of conditions.
+   */
+  public function getConditions() {
+    return $this->conditions;
+  }
+
+  /**
+   * Returns the ID of the plugin that is being removed.
+   *
+   * @return string
+   *   The plugin ID.
+   */
+  public function getPluginId() {
+    return $this->pluginId;
+  }
+
+  /**
+   * Returns the plugin type of the plugin that is being removed.
+   *
+   * @return string
+   */
+  public function getPluginType() {
+    return $this->pluginType;
+  }
+
+}
diff --git a/core/lib/Drupal/Core/Plugin/PluginEvents.php b/core/lib/Drupal/Core/Plugin/PluginEvents.php
new file mode 100644
index 0000000..e61fa62
--- /dev/null
+++ b/core/lib/Drupal/Core/Plugin/PluginEvents.php
@@ -0,0 +1,23 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\Plugin\PluginEvents.
+ */
+
+namespace Drupal\Core\Plugin;
+
+/**
+ * Defines events for plugins.
+ */
+class PluginEvents {
+
+  /**
+   * This event is fired when a plugin becomes unavailable.
+   *
+   * This could occur for example when a module is uninstalled or the data from
+   * which a plugin is derived is deleted.
+   */
+  const REMOVAL = 'plugin.removal';
+
+}
diff --git a/core/lib/Drupal/Core/Queue/QueueWorkerManager.php b/core/lib/Drupal/Core/Queue/QueueWorkerManager.php
index 6339065..12114c2 100644
--- a/core/lib/Drupal/Core/Queue/QueueWorkerManager.php
+++ b/core/lib/Drupal/Core/Queue/QueueWorkerManager.php
@@ -10,6 +10,7 @@
 use Drupal\Core\Cache\CacheBackendInterface;
 use Drupal\Core\Extension\ModuleHandlerInterface;
 use Drupal\Core\Plugin\DefaultPluginManager;
+use Symfony\Component\EventDispatcher\EventDispatcherInterface;
 
 /**
  * Defines the queue worker manager.
@@ -31,9 +32,11 @@ class QueueWorkerManager extends DefaultPluginManager implements QueueWorkerMana
    *   Cache backend instance to use.
    * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
    *   The module handler.
+   * @param \Symfony\Component\EventDispatcher\EventDispatcherInterface $event_dispatcher
+   *   The event dispatcher.
    */
-  public function __construct(\Traversable $namespaces, CacheBackendInterface $cache_backend, ModuleHandlerInterface $module_handler) {
-    parent::__construct('Plugin/QueueWorker', $namespaces, $module_handler, 'Drupal\Core\Queue\QueueWorkerInterface', 'Drupal\Core\Annotation\QueueWorker');
+  public function __construct(\Traversable $namespaces, CacheBackendInterface $cache_backend, ModuleHandlerInterface $module_handler, EventDispatcherInterface $event_dispatcher) {
+    parent::__construct('Plugin/QueueWorker', $namespaces, $module_handler, $event_dispatcher, 'Drupal\Core\Queue\QueueWorkerInterface', 'Drupal\Core\Annotation\QueueWorker');
 
     $this->setCacheBackend($cache_backend, 'queue_plugins');
     $this->alterInfo('queue_info');
diff --git a/core/lib/Drupal/Core/Render/ElementInfoManager.php b/core/lib/Drupal/Core/Render/ElementInfoManager.php
index 784fdef..501a4af 100644
--- a/core/lib/Drupal/Core/Render/ElementInfoManager.php
+++ b/core/lib/Drupal/Core/Render/ElementInfoManager.php
@@ -11,6 +11,7 @@
 use Drupal\Core\Extension\ModuleHandlerInterface;
 use Drupal\Core\Plugin\DefaultPluginManager;
 use Drupal\Core\Render\Element\FormElementInterface;
+use Symfony\Component\EventDispatcher\EventDispatcherInterface;
 
 /**
  * Provides a plugin manager for element plugins.
@@ -42,11 +43,13 @@ class ElementInfoManager extends DefaultPluginManager implements ElementInfoMana
    *   Cache backend instance to use.
    * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
    *   The module handler to invoke the alter hook with.
+   * @param \Symfony\Component\EventDispatcher\EventDispatcherInterface $event_dispatcher
+   *   The event dispatcher.
    */
-  public function __construct(\Traversable $namespaces, CacheBackendInterface $cache_backend, ModuleHandlerInterface $module_handler) {
+  public function __construct(\Traversable $namespaces, CacheBackendInterface $cache_backend, ModuleHandlerInterface $module_handler, EventDispatcherInterface $event_dispatcher) {
     $this->setCacheBackend($cache_backend, 'element_info');
 
-    parent::__construct('Element', $namespaces, $module_handler, 'Drupal\Core\Render\Element\ElementInterface', 'Drupal\Core\Render\Annotation\RenderElement');
+    parent::__construct('Element', $namespaces, $module_handler, $event_dispatcher, 'Drupal\Core\Render\Element\ElementInterface', 'Drupal\Core\Render\Annotation\RenderElement');
   }
 
   /**
diff --git a/core/lib/Drupal/Core/TypedData/TypedDataManager.php b/core/lib/Drupal/Core/TypedData/TypedDataManager.php
index 726ae38..a87b314 100644
--- a/core/lib/Drupal/Core/TypedData/TypedDataManager.php
+++ b/core/lib/Drupal/Core/TypedData/TypedDataManager.php
@@ -15,6 +15,7 @@
 use Drupal\Core\TypedData\Validation\MetadataFactory;
 use Drupal\Core\Validation\ConstraintManager;
 use Drupal\Core\Validation\DrupalTranslator;
+use Symfony\Component\EventDispatcher\EventDispatcherInterface;
 use Symfony\Component\Validator\ValidatorInterface;
 use Symfony\Component\Validator\Validation;
 
@@ -54,12 +55,14 @@ class TypedDataManager extends DefaultPluginManager {
   *   Cache backend instance to use.
   * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
   *   The module handler.
+  * @param \Symfony\Component\EventDispatcher\EventDispatcherInterface $event_dispatcher
+  *   The event dispatcher.
   */
-  public function __construct(\Traversable $namespaces, CacheBackendInterface $cache_backend, ModuleHandlerInterface $module_handler) {
+  public function __construct(\Traversable $namespaces, CacheBackendInterface $cache_backend, ModuleHandlerInterface $module_handler, EventDispatcherInterface $event_dispatcher) {
     $this->alterInfo('data_type_info');
     $this->setCacheBackend($cache_backend, 'typed_data_types_plugins');
 
-    parent::__construct('Plugin/DataType', $namespaces, $module_handler, NULL, 'Drupal\Core\TypedData\Annotation\DataType');
+    parent::__construct('Plugin/DataType', $namespaces, $module_handler, $event_dispatcher, NULL, 'Drupal\Core\TypedData\Annotation\DataType');
   }
 
   /**
diff --git a/core/lib/Drupal/Core/Validation/ConstraintManager.php b/core/lib/Drupal/Core/Validation/ConstraintManager.php
index a2b46d3..a543230 100644
--- a/core/lib/Drupal/Core/Validation/ConstraintManager.php
+++ b/core/lib/Drupal/Core/Validation/ConstraintManager.php
@@ -12,6 +12,7 @@
 use Drupal\Core\Extension\ModuleHandlerInterface;
 use Drupal\Core\Plugin\DefaultPluginManager;
 use Drupal\Core\StringTranslation\TranslationWrapper;
+use Symfony\Component\EventDispatcher\EventDispatcherInterface;
 
 /**
  * Constraint plugin manager.
@@ -43,9 +44,11 @@ class ConstraintManager extends DefaultPluginManager {
    *   Cache backend instance to use.
    * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
    *   The module handler to invoke the alter hook with.
+   * @param \Symfony\Component\EventDispatcher\EventDispatcherInterface $event_dispatcher
+   *   The event dispatcher.
    */
-  public function __construct(\Traversable $namespaces, CacheBackendInterface $cache_backend, ModuleHandlerInterface $module_handler) {
-    parent::__construct('Plugin/Validation/Constraint', $namespaces, $module_handler);
+  public function __construct(\Traversable $namespaces, CacheBackendInterface $cache_backend, ModuleHandlerInterface $module_handler, EventDispatcherInterface $event_dispatcher) {
+    parent::__construct('Plugin/Validation/Constraint', $namespaces, $module_handler, $event_dispatcher);
     $this->discovery = new StaticDiscoveryDecorator($this->discovery, array($this, 'registerDefinitions'));
     $this->alterInfo('validation_constraint');
     $this->setCacheBackend($cache_backend, 'validation_constraint_plugins');
diff --git a/core/modules/aggregator/aggregator.services.yml b/core/modules/aggregator/aggregator.services.yml
index 6b191c8..1fab7c1 100644
--- a/core/modules/aggregator/aggregator.services.yml
+++ b/core/modules/aggregator/aggregator.services.yml
@@ -1,13 +1,13 @@
 services:
   plugin.manager.aggregator.fetcher:
     class: Drupal\aggregator\Plugin\AggregatorPluginManager
-    arguments: [fetcher, '@container.namespaces', '@cache.discovery', '@module_handler']
+    arguments: [fetcher, '@container.namespaces', '@cache.discovery', '@module_handler', '@event_dispatcher']
   plugin.manager.aggregator.parser:
     class: Drupal\aggregator\Plugin\AggregatorPluginManager
-    arguments: [parser, '@container.namespaces', '@cache.discovery', '@module_handler']
+    arguments: [parser, '@container.namespaces', '@cache.discovery', '@module_handler', '@event_dispatcher']
   plugin.manager.aggregator.processor:
     class: Drupal\aggregator\Plugin\AggregatorPluginManager
-    arguments: [processor, '@container.namespaces', '@cache.discovery', '@module_handler']
+    arguments: [processor, '@container.namespaces', '@cache.discovery', '@module_handler', '@event_dispatcher']
   aggregator.items.importer:
     class: Drupal\aggregator\ItemsImporter
     arguments: ['@config.factory', '@plugin.manager.aggregator.fetcher', '@plugin.manager.aggregator.parser', '@plugin.manager.aggregator.processor', '@logger.channel.aggregator']
diff --git a/core/modules/aggregator/src/Entity/Feed.php b/core/modules/aggregator/src/Entity/Feed.php
index 5bcd787..33cc9e5 100644
--- a/core/modules/aggregator/src/Entity/Feed.php
+++ b/core/modules/aggregator/src/Entity/Feed.php
@@ -113,15 +113,12 @@ public static function preDelete(EntityStorageInterface $storage, array $entitie
    */
   public static function postDelete(EntityStorageInterface $storage, array $entities) {
     parent::postDelete($storage, $entities);
-    if (\Drupal::moduleHandler()->moduleExists('block')) {
-      // Make sure there are no active blocks for these feeds.
-      $ids = \Drupal::entityQuery('block')
-        ->condition('plugin', 'aggregator_feed_block')
-        ->condition('settings.feed', array_keys($entities))
-        ->execute();
-      if ($ids) {
-        $block_storage = \Drupal::entityManager()->getStorage('block');
-        $block_storage->delete($block_storage->loadMultiple($ids));
+
+    // Make sure there are no active blocks for these feeds.
+    /** @var \Drupal\Core\Plugin\DefaultPluginManagerInterface $block_manager */
+    if (\Drupal::hasService('plugin.manager.block') && $block_manager = \Drupal::service('plugin.manager.block')) {
+      foreach ($entities as $entity) {
+        $block_manager->removePlugin('aggregator_feed_block', FALSE, array('settings.feed' => $entity->id()));
       }
     }
   }
diff --git a/core/modules/aggregator/src/Plugin/AggregatorPluginManager.php b/core/modules/aggregator/src/Plugin/AggregatorPluginManager.php
index e1cccc7..f98aa88 100644
--- a/core/modules/aggregator/src/Plugin/AggregatorPluginManager.php
+++ b/core/modules/aggregator/src/Plugin/AggregatorPluginManager.php
@@ -10,6 +10,7 @@
 use Drupal\Core\Cache\CacheBackendInterface;
 use Drupal\Core\Extension\ModuleHandlerInterface;
 use Drupal\Core\Plugin\DefaultPluginManager;
+use Symfony\Component\EventDispatcher\EventDispatcherInterface;
 
 /**
  * Manages aggregator plugins.
@@ -37,8 +38,10 @@ class AggregatorPluginManager extends DefaultPluginManager {
    *   Cache backend instance to use.
    * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
    *   The module handler.
+   * @param \Symfony\Component\EventDispatcher\EventDispatcherInterface $event_dispatcher
+   *   The event dispatcher.
    */
-  public function __construct($type, \Traversable $namespaces, CacheBackendInterface $cache_backend, ModuleHandlerInterface $module_handler) {
+  public function __construct($type, \Traversable $namespaces, CacheBackendInterface $cache_backend, ModuleHandlerInterface $module_handler, EventDispatcherInterface $event_dispatcher) {
     $type_annotations = array(
       'fetcher' => 'Drupal\aggregator\Annotation\AggregatorFetcher',
       'parser' => 'Drupal\aggregator\Annotation\AggregatorParser',
@@ -50,7 +53,7 @@ public function __construct($type, \Traversable $namespaces, CacheBackendInterfa
       'processor' => 'Drupal\aggregator\Plugin\ProcessorInterface',
     );
 
-    parent::__construct("Plugin/aggregator/$type", $namespaces, $module_handler, $plugin_interfaces[$type], $type_annotations[$type]);
+    parent::__construct("Plugin/aggregator/$type", $namespaces, $module_handler, $event_dispatcher, $plugin_interfaces[$type], $type_annotations[$type]);
     $this->setCacheBackend($cache_backend, 'aggregator_' . $type . '_plugins');
   }
 
diff --git a/core/modules/aggregator/src/Tests/AggregatorRenderingTest.php b/core/modules/aggregator/src/Tests/AggregatorRenderingTest.php
index 844f0b1..8a710f5 100644
--- a/core/modules/aggregator/src/Tests/AggregatorRenderingTest.php
+++ b/core/modules/aggregator/src/Tests/AggregatorRenderingTest.php
@@ -77,6 +77,17 @@ public function testBlockLinks() {
     // Check that the block is no longer displayed.
     $this->drupalGet('test-page');
     $this->assertNoText($block->label(), 'Feed block is not displayed on the page when number of items is set to 0.');
+
+    // Set the number of news items to 5 to test that the block shows again.
+    $block->getPlugin()->setConfigurationValue('block_count', 5);
+    $block->save();
+    $this->drupalGet('test-page');
+    $this->assertText($block->label(), 'Feed block is displayed again on the page when number of items is set to 5.');
+
+    // Delete the feed and check that the block is no longer displayed.
+    $feed->delete();
+    $this->drupalGet('test-page');
+    $this->assertNoText($block->label(), 'Feed block is not displayed on the page once deleted.');
   }
 
   /**
diff --git a/core/modules/block/block.services.yml b/core/modules/block/block.services.yml
index dd38a43..f7e8c5f 100644
--- a/core/modules/block/block.services.yml
+++ b/core/modules/block/block.services.yml
@@ -18,3 +18,8 @@ services:
     arguments: ['@current_route_match']
     tags:
       - { name: 'event_subscriber' }
+  block.entity.event.subscriber:
+    class: Drupal\block\BlockEntityBlockEventSubscriber
+    arguments: ['@entity.query', '@entity.manager']
+    tags:
+      - { name: event_subscriber }
diff --git a/core/modules/block/src/BlockEntityBlockEventSubscriber.php b/core/modules/block/src/BlockEntityBlockEventSubscriber.php
new file mode 100644
index 0000000..65443e6
--- /dev/null
+++ b/core/modules/block/src/BlockEntityBlockEventSubscriber.php
@@ -0,0 +1,75 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\block\BlockEntityBlockEventSubscriber.
+ */
+
+namespace Drupal\block;
+
+use Drupal\Core\Entity\EntityManagerInterface;
+use Drupal\Core\Entity\Query\QueryFactory;
+use Drupal\Core\Plugin\Event\PluginRemovalEvent;
+use Drupal\Core\Plugin\PluginEvents;
+use Symfony\Component\EventDispatcher\EventSubscriberInterface;
+
+/**
+ * Contains block entity responses to block plugin events.
+ */
+class BlockEntityBlockEventSubscriber implements EventSubscriberInterface {
+
+  /**
+   * The entity query factory.
+   *
+   * @var \Drupal\Core\Entity\Query\QueryFactory
+   */
+  protected $queryFactory;
+
+  /**
+   * The block storage controller.
+   *
+   * @var \Drupal\Core\Entity\EntityStorageInterface
+   */
+  protected $blockStorageController;
+
+  /**
+   * Constructs a \Drupal\block\BlockEntityBlockEventSubscriber object.
+   *
+   * @param \Drupal\Core\Entity\Query\QueryFactory $query_factory
+   *   The entity query factory.
+   * @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
+   *   The entity manager.
+   */
+  public function __construct(QueryFactory $query_factory, EntityManagerInterface $entity_manager) {
+    $this->queryFactory = $query_factory;
+    $this->blockStorageController = $entity_manager->getStorage('block');
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function getSubscribedEvents() {
+    $events[PluginEvents::REMOVAL][] = 'deleteEntityByPlugin';
+
+    return $events;
+  }
+
+  /**
+   * Reacts on removing a block plugin.
+   */
+  public function deleteEntityByPlugin(PluginRemovalEvent $event) {
+    if ($event->getPluginType() != 'plugin_block') {
+      return;
+    }
+    $query = $this->queryFactory->get('block');
+    $query->condition('plugin', $event->getPluginId());
+    foreach ($event->getConditions() as $condition => $value) {
+      $query->condition($condition, $value);
+    }
+    $result = $query->execute();
+    if ($blocks = $this->blockStorageController->loadMultiple($result)) {
+      $this->blockStorageController->delete($blocks);
+    }
+  }
+
+}
diff --git a/core/modules/block_content/src/Entity/BlockContent.php b/core/modules/block_content/src/Entity/BlockContent.php
index 2d035ec..f75181f 100644
--- a/core/modules/block_content/src/Entity/BlockContent.php
+++ b/core/modules/block_content/src/Entity/BlockContent.php
@@ -129,9 +129,11 @@ public function preSaveRevision(EntityStorageInterface $storage, \stdClass $reco
    * {@inheritdoc}
    */
   public function delete() {
-    foreach ($this->getInstances() as $instance) {
-      $instance->delete();
-    }
+    // Allow subscribers to react to the removal of the block.
+    /** @var \Drupal\block\BlockManagerInterface $block_manager */
+    $block_manager = \Drupal::service('plugin.manager.block');
+    $block_manager->removePlugin('block_content:' . $this->uuid());
+
     parent::delete();
   }
 
diff --git a/core/modules/ckeditor/src/CKEditorPluginManager.php b/core/modules/ckeditor/src/CKEditorPluginManager.php
index 1f05833..cca71bb 100644
--- a/core/modules/ckeditor/src/CKEditorPluginManager.php
+++ b/core/modules/ckeditor/src/CKEditorPluginManager.php
@@ -13,6 +13,7 @@
 use Drupal\Core\Cache\CacheBackendInterface;
 use Drupal\Core\Extension\ModuleHandlerInterface;
 use Drupal\editor\Entity\Editor;
+use Symfony\Component\EventDispatcher\EventDispatcherInterface;
 
 /**
  * Provides a CKEditor Plugin plugin manager.
@@ -37,9 +38,11 @@ class CKEditorPluginManager extends DefaultPluginManager {
    *   Cache backend instance to use.
    * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
    *   The module handler to invoke the alter hook with.
+   * @param \Symfony\Component\EventDispatcher\EventDispatcherInterface $event_dispatcher
+   *   The event dispatcher.
    */
-  public function __construct(\Traversable $namespaces, CacheBackendInterface $cache_backend, ModuleHandlerInterface $module_handler) {
-    parent::__construct('Plugin/CKEditorPlugin', $namespaces, $module_handler, 'Drupal\ckeditor\CKEditorPluginInterface', 'Drupal\ckeditor\Annotation\CKEditorPlugin');
+  public function __construct(\Traversable $namespaces, CacheBackendInterface $cache_backend, ModuleHandlerInterface $module_handler, EventDispatcherInterface $event_dispatcher) {
+    parent::__construct('Plugin/CKEditorPlugin', $namespaces, $module_handler, $event_dispatcher, 'Drupal\ckeditor\CKEditorPluginInterface', 'Drupal\ckeditor\Annotation\CKEditorPlugin');
     $this->alterInfo('ckeditor_plugin_info');
     $this->setCacheBackend($cache_backend, 'ckeditor_plugins');
   }
diff --git a/core/modules/config/src/Tests/DefaultConfigTest.php b/core/modules/config/src/Tests/DefaultConfigTest.php
index 4880561..254502a 100644
--- a/core/modules/config/src/Tests/DefaultConfigTest.php
+++ b/core/modules/config/src/Tests/DefaultConfigTest.php
@@ -38,7 +38,8 @@ public function testDefaultConfig() {
       \Drupal::service('config.storage'),
       new TestInstallStorage(InstallStorage::CONFIG_SCHEMA_DIRECTORY),
       \Drupal::service('cache.discovery'),
-      \Drupal::service('module_handler')
+      \Drupal::service('module_handler'),
+      \Drupal::service('event_dispatcher')
     );
 
     // Create a configuration storage with access to default configuration in
diff --git a/core/modules/config_translation/config_translation.services.yml b/core/modules/config_translation/config_translation.services.yml
index e6c00b6..e760fda 100644
--- a/core/modules/config_translation/config_translation.services.yml
+++ b/core/modules/config_translation/config_translation.services.yml
@@ -23,5 +23,6 @@ services:
       - '@cache.default'
       - '@language_manager'
       - '@module_handler'
+      - '@event_dispatcher'
       - '@config.typed'
       - '@theme_handler'
diff --git a/core/modules/config_translation/src/ConfigMapperManager.php b/core/modules/config_translation/src/ConfigMapperManager.php
index 9a0b46e..ed056bb 100644
--- a/core/modules/config_translation/src/ConfigMapperManager.php
+++ b/core/modules/config_translation/src/ConfigMapperManager.php
@@ -21,6 +21,7 @@
 use Drupal\Core\Plugin\Discovery\ContainerDerivativeDiscoveryDecorator;
 use Drupal\Core\Plugin\Factory\ContainerFactory;
 use Drupal\Core\TypedData\TypedDataInterface;
+use Symfony\Component\EventDispatcher\EventDispatcherInterface;
 use Symfony\Component\Routing\RouteCollection;
 
 /**
@@ -61,10 +62,12 @@ class ConfigMapperManager extends DefaultPluginManager implements ConfigMapperMa
    *   The language manager.
    * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
    *   The module handler.
+   * @param \Symfony\Component\EventDispatcher\EventDispatcherInterface $event_dispatcher
+   *   The event dispatcher.
    * @param \Drupal\Core\Config\TypedConfigManagerInterface $typed_config_manager
    *   The typed config manager.
    */
-  public function __construct(CacheBackendInterface $cache_backend, LanguageManagerInterface $language_manager, ModuleHandlerInterface $module_handler, TypedConfigManagerInterface $typed_config_manager, ThemeHandlerInterface $theme_handler) {
+  public function __construct(CacheBackendInterface $cache_backend, LanguageManagerInterface $language_manager, ModuleHandlerInterface $module_handler, EventDispatcherInterface $event_dispatcher, TypedConfigManagerInterface $typed_config_manager, ThemeHandlerInterface $theme_handler) {
     $this->typedConfigManager = $typed_config_manager;
 
     // Look at all themes and modules.
@@ -94,6 +97,7 @@ public function __construct(CacheBackendInterface $cache_backend, LanguageManage
 
     // Let others alter definitions with hook_config_translation_info_alter().
     $this->moduleHandler = $module_handler;
+    $this->eventDispatcher = $event_dispatcher;
     $this->themeHandler = $theme_handler;
 
     $this->alterInfo('config_translation_info');
diff --git a/core/modules/config_translation/tests/src/Unit/ConfigMapperManagerTest.php b/core/modules/config_translation/tests/src/Unit/ConfigMapperManagerTest.php
index c28b663..66677dd 100644
--- a/core/modules/config_translation/tests/src/Unit/ConfigMapperManagerTest.php
+++ b/core/modules/config_translation/tests/src/Unit/ConfigMapperManagerTest.php
@@ -56,11 +56,13 @@ protected function setUp() {
     $theme_handler->expects($this->any())
       ->method('listInfo')
       ->will($this->returnValue(array()));
+    $event_dispatcher = $this->getMock('Symfony\Component\EventDispatcher\EventDispatcherInterface');
 
     $this->configMapperManager = new ConfigMapperManager(
       $this->getMock('Drupal\Core\Cache\CacheBackendInterface'),
       $language_manager,
       $module_handler,
+      $event_dispatcher,
       $this->typedConfigManager,
       $theme_handler
     );
diff --git a/core/modules/editor/src/Plugin/EditorManager.php b/core/modules/editor/src/Plugin/EditorManager.php
index da0081e..7dbca6b 100644
--- a/core/modules/editor/src/Plugin/EditorManager.php
+++ b/core/modules/editor/src/Plugin/EditorManager.php
@@ -10,6 +10,7 @@
 use Drupal\Core\Plugin\DefaultPluginManager;
 use Drupal\Core\Cache\CacheBackendInterface;
 use Drupal\Core\Extension\ModuleHandlerInterface;
+use Symfony\Component\EventDispatcher\EventDispatcherInterface;
 
 /**
  * Configurable text editor manager.
@@ -31,9 +32,11 @@ class EditorManager extends DefaultPluginManager {
    *   Cache backend instance to use.
    * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
    *   The module handler to invoke the alter hook with.
+   * @param \Symfony\Component\EventDispatcher\EventDispatcherInterface $event_dispatcher
+   *   The event dispatcher.
    */
-  public function __construct(\Traversable $namespaces, CacheBackendInterface $cache_backend, ModuleHandlerInterface $module_handler) {
-    parent::__construct('Plugin/Editor', $namespaces, $module_handler, 'Drupal\editor\Plugin\EditorPluginInterface', 'Drupal\editor\Annotation\Editor');
+  public function __construct(\Traversable $namespaces, CacheBackendInterface $cache_backend, ModuleHandlerInterface $module_handler, EventDispatcherInterface $event_dispatcher) {
+    parent::__construct('Plugin/Editor', $namespaces, $module_handler, $event_dispatcher, 'Drupal\editor\Plugin\EditorPluginInterface', 'Drupal\editor\Annotation\Editor');
     $this->alterInfo('editor_info');
     $this->setCacheBackend($cache_backend, 'editor_plugins');
   }
diff --git a/core/modules/entity_reference/src/Plugin/Type/SelectionPluginManager.php b/core/modules/entity_reference/src/Plugin/Type/SelectionPluginManager.php
index b4e17a1..d5b445c 100644
--- a/core/modules/entity_reference/src/Plugin/Type/SelectionPluginManager.php
+++ b/core/modules/entity_reference/src/Plugin/Type/SelectionPluginManager.php
@@ -16,6 +16,7 @@
 use Drupal\Core\Plugin\DefaultPluginManager;
 use Drupal\Core\Plugin\Discovery\AnnotatedClassDiscovery;
 use Drupal\entity_reference\Plugin\Type\Selection\SelectionBroken;
+use Symfony\Component\EventDispatcher\EventDispatcherInterface;
 
 /**
  * Plugin type manager for Entity Reference Selection plugins.
@@ -31,7 +32,7 @@ class SelectionPluginManager extends DefaultPluginManager {
   /**
    * {@inheritdoc}
    */
-  public function __construct(\Traversable $namespaces, CacheBackendInterface $cache_backend, ModuleHandlerInterface $module_handler) {
+  public function __construct(\Traversable $namespaces, CacheBackendInterface $cache_backend, ModuleHandlerInterface $module_handler, EventDispatcherInterface $event_dispatcher) {
     $this->discovery = new AnnotatedClassDiscovery('Plugin/entity_reference/selection', $namespaces, 'Drupal\entity_reference\Annotation\EntityReferenceSelection');
 
     // We're not using the parent constructor because we use a different factory
@@ -39,6 +40,7 @@ public function __construct(\Traversable $namespaces, CacheBackendInterface $cac
     $this->factory = new ReflectionFactory($this, '\Drupal\entity_reference\Plugin\Type\Selection\SelectionInterface');
 
     $this->moduleHandler = $module_handler;
+    $this->eventDispatcher = $event_dispatcher;
     $this->alterInfo('entity_reference_selection');
     $this->setCacheBackend($cache_backend, 'entity_reference_selection_plugins');
   }
diff --git a/core/modules/filter/src/FilterPluginManager.php b/core/modules/filter/src/FilterPluginManager.php
index 43b6568..e7f751b 100644
--- a/core/modules/filter/src/FilterPluginManager.php
+++ b/core/modules/filter/src/FilterPluginManager.php
@@ -11,6 +11,7 @@
 use Drupal\Core\Cache\CacheBackendInterface;
 use Drupal\Core\Extension\ModuleHandlerInterface;
 use Drupal\Core\Plugin\DefaultPluginManager;
+use Symfony\Component\EventDispatcher\EventDispatcherInterface;
 
 /**
  * Manages text processing filters.
@@ -33,9 +34,11 @@ class FilterPluginManager extends DefaultPluginManager implements FallbackPlugin
    *   Cache backend instance to use.
    * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
    *   The module handler to invoke the alter hook with.
+   * @param \Symfony\Component\EventDispatcher\EventDispatcherInterface $event_dispatcher
+   *   The event dispatcher.
    */
-  public function __construct(\Traversable $namespaces, CacheBackendInterface $cache_backend, ModuleHandlerInterface $module_handler) {
-    parent::__construct('Plugin/Filter', $namespaces, $module_handler, 'Drupal\filter\Plugin\FilterInterface', 'Drupal\filter\Annotation\Filter');
+  public function __construct(\Traversable $namespaces, CacheBackendInterface $cache_backend, ModuleHandlerInterface $module_handler, EventDispatcherInterface $event_dispatcher) {
+    parent::__construct('Plugin/Filter', $namespaces, $module_handler, $event_dispatcher, 'Drupal\filter\Plugin\FilterInterface', 'Drupal\filter\Annotation\Filter');
     $this->alterInfo('filter_info');
     $this->setCacheBackend($cache_backend, 'filter_plugins', array('filter_formats'));
   }
diff --git a/core/modules/image/src/ImageEffectManager.php b/core/modules/image/src/ImageEffectManager.php
index aa4c24b..45311df 100644
--- a/core/modules/image/src/ImageEffectManager.php
+++ b/core/modules/image/src/ImageEffectManager.php
@@ -10,6 +10,7 @@
 use Drupal\Core\Cache\CacheBackendInterface;
 use Drupal\Core\Extension\ModuleHandlerInterface;
 use Drupal\Core\Plugin\DefaultPluginManager;
+use Symfony\Component\EventDispatcher\EventDispatcherInterface;
 
 /**
  * Manages image effect plugins.
@@ -34,9 +35,11 @@ class ImageEffectManager extends DefaultPluginManager {
    *   Cache backend instance to use.
    * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
    *   The module handler.
+   * @param \Symfony\Component\EventDispatcher\EventDispatcherInterface $event_dispatcher
+   *   The event dispatcher.
    */
-  public function __construct(\Traversable $namespaces, CacheBackendInterface $cache_backend, ModuleHandlerInterface $module_handler) {
-    parent::__construct('Plugin/ImageEffect', $namespaces, $module_handler, 'Drupal\image\ImageEffectInterface', 'Drupal\image\Annotation\ImageEffect');
+  public function __construct(\Traversable $namespaces, CacheBackendInterface $cache_backend, ModuleHandlerInterface $module_handler, EventDispatcherInterface $event_dispatcher) {
+    parent::__construct('Plugin/ImageEffect', $namespaces, $module_handler, $event_dispatcher, 'Drupal\image\ImageEffectInterface', 'Drupal\image\Annotation\ImageEffect');
 
     $this->alterInfo('image_effect_info');
     $this->setCacheBackend($cache_backend, 'image_effect_plugins');
diff --git a/core/modules/language/language.services.yml b/core/modules/language/language.services.yml
index eae3af5..05a41f8 100644
--- a/core/modules/language/language.services.yml
+++ b/core/modules/language/language.services.yml
@@ -1,7 +1,7 @@
 services:
   plugin.manager.language_negotiation_method:
     class: Drupal\language\LanguageNegotiationMethodManager
-    arguments: ['@container.namespaces', '@cache.discovery', '@module_handler']
+    arguments: ['@container.namespaces', '@cache.discovery', '@module_handler', '@event_dispatcher']
   language_negotiator:
     class: Drupal\language\LanguageNegotiator
     arguments: ['@language_manager', '@plugin.manager.language_negotiation_method', '@config.factory', '@settings', '@request_stack']
diff --git a/core/modules/language/src/LanguageNegotiationMethodManager.php b/core/modules/language/src/LanguageNegotiationMethodManager.php
index b263ed5..e9cc4f8 100644
--- a/core/modules/language/src/LanguageNegotiationMethodManager.php
+++ b/core/modules/language/src/LanguageNegotiationMethodManager.php
@@ -10,6 +10,7 @@
 use Drupal\Core\Cache\CacheBackendInterface;
 use Drupal\Core\Extension\ModuleHandlerInterface;
 use Drupal\Core\Plugin\DefaultPluginManager;
+use Symfony\Component\EventDispatcher\EventDispatcherInterface;
 
 /**
  * Manages language negotiation methods.
@@ -26,9 +27,11 @@ class LanguageNegotiationMethodManager extends DefaultPluginManager {
    *   An object that implements CacheBackendInterface
    * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
    *   An object that implements ModuleHandlerInterface
+   * @param \Symfony\Component\EventDispatcher\EventDispatcherInterface $event_dispatcher
+   *   The event dispatcher.
    */
-  public function __construct(\Traversable $namespaces, CacheBackendInterface $cache_backend, ModuleHandlerInterface $module_handler) {
-    parent::__construct('Plugin/LanguageNegotiation', $namespaces, $module_handler, 'Drupal\language\LanguageNegotiationMethodInterface');
+  public function __construct(\Traversable $namespaces, CacheBackendInterface $cache_backend, ModuleHandlerInterface $module_handler, EventDispatcherInterface $event_dispatcher) {
+    parent::__construct('Plugin/LanguageNegotiation', $namespaces, $module_handler, $event_dispatcher, 'Drupal\language\LanguageNegotiationMethodInterface');
     $this->cacheBackend = $cache_backend;
     $this->cacheKeyPrefix = 'language_negotiation_plugins';
     $this->cacheKey = 'language_negotiation_plugins';
diff --git a/core/modules/migrate/migrate.services.yml b/core/modules/migrate/migrate.services.yml
index 8b6bad7..26f4774 100644
--- a/core/modules/migrate/migrate.services.yml
+++ b/core/modules/migrate/migrate.services.yml
@@ -8,16 +8,16 @@ services:
     arguments: [migrate]
   plugin.manager.migrate.source:
     class: Drupal\migrate\Plugin\MigratePluginManager
-    arguments: [source, '@container.namespaces', '@cache.discovery', '@module_handler', 'Drupal\migrate\Annotation\MigrateSource']
+    arguments: [source, '@container.namespaces', '@cache.discovery', '@module_handler', '@event_dispatcher', 'Drupal\migrate\Annotation\MigrateSource']
   plugin.manager.migrate.process:
     class: Drupal\migrate\Plugin\MigratePluginManager
-    arguments: [process, '@container.namespaces', '@cache.discovery', '@module_handler', 'Drupal\migrate\Annotation\MigrateProcessPlugin']
+    arguments: [process, '@container.namespaces', '@cache.discovery', '@module_handler', '@event_dispatcher', 'Drupal\migrate\Annotation\MigrateProcessPlugin']
   plugin.manager.migrate.destination:
     class: Drupal\migrate\Plugin\MigrateDestinationPluginManager
-    arguments: [destination, '@container.namespaces', '@cache.discovery', '@module_handler', '@entity.manager']
+    arguments: [destination, '@container.namespaces', '@cache.discovery', '@module_handler', '@event_dispatcher', '@entity.manager']
   plugin.manager.migrate.id_map:
     class: Drupal\migrate\Plugin\MigratePluginManager
-    arguments: [id_map, '@container.namespaces', '@cache.discovery', '@module_handler']
+    arguments: [id_map, '@container.namespaces', '@cache.discovery', '@module_handler', '@event_dispatcher']
   password_migrate:
     class: Drupal\migrate\MigratePassword
     arguments: ['@password_original']
diff --git a/core/modules/migrate/src/Plugin/MigrateDestinationPluginManager.php b/core/modules/migrate/src/Plugin/MigrateDestinationPluginManager.php
index b8f187d..c513874 100644
--- a/core/modules/migrate/src/Plugin/MigrateDestinationPluginManager.php
+++ b/core/modules/migrate/src/Plugin/MigrateDestinationPluginManager.php
@@ -12,6 +12,7 @@
 use Drupal\Core\Entity\EntityManagerInterface;
 use Drupal\Core\Extension\ModuleHandlerInterface;
 use Drupal\migrate\Entity\MigrationInterface;
+use Symfony\Component\EventDispatcher\EventDispatcherInterface;
 
 /**
  * Plugin manager for migrate destination plugins.
@@ -42,8 +43,8 @@ class MigrateDestinationPluginManager extends MigratePluginManager {
   /**
    * {@inheritdoc}
    */
-  public function __construct($type, \Traversable $namespaces, CacheBackendInterface $cache_backend, ModuleHandlerInterface $module_handler, EntityManagerInterface $entity_manager, $annotation = 'Drupal\migrate\Annotation\MigrateDestination') {
-    parent::__construct($type, $namespaces, $cache_backend, $module_handler, $annotation);
+  public function __construct($type, \Traversable $namespaces, CacheBackendInterface $cache_backend, ModuleHandlerInterface $module_handler, EventDispatcherInterface $event_dispatcher, EntityManagerInterface $entity_manager, $annotation = 'Drupal\migrate\Annotation\MigrateDestination') {
+    parent::__construct($type, $namespaces, $cache_backend, $module_handler, $event_dispatcher, $annotation);
     $this->entityManager = $entity_manager;
   }
 
diff --git a/core/modules/migrate/src/Plugin/MigratePluginManager.php b/core/modules/migrate/src/Plugin/MigratePluginManager.php
index 67cce89..411eef1 100644
--- a/core/modules/migrate/src/Plugin/MigratePluginManager.php
+++ b/core/modules/migrate/src/Plugin/MigratePluginManager.php
@@ -12,6 +12,7 @@
 use Drupal\Core\Extension\ModuleHandlerInterface;
 use Drupal\Core\Plugin\DefaultPluginManager;
 use Drupal\migrate\Entity\MigrationInterface;
+use Symfony\Component\EventDispatcher\EventDispatcherInterface;
 
 /**
  * Manages migrate plugins.
@@ -42,10 +43,12 @@ class MigratePluginManager extends DefaultPluginManager {
    *   Cache backend instance to use.
    * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
    *   The module handler to invoke the alter hook with.
+   * @param \Symfony\Component\EventDispatcher\EventDispatcherInterface $event_dispatcher
+   *   The event dispatcher.
    * @param string $annotation
    *   The annotation class name.
    */
-  public function __construct($type, \Traversable $namespaces, CacheBackendInterface $cache_backend, ModuleHandlerInterface $module_handler, $annotation = 'Drupal\Component\Annotation\PluginID') {
+  public function __construct($type, \Traversable $namespaces, CacheBackendInterface $cache_backend, ModuleHandlerInterface $module_handler, EventDispatcherInterface $event_dispatcher, $annotation = 'Drupal\Component\Annotation\PluginID') {
     $plugin_interface_map = array(
       'destination' => 'Drupal\migrate\Plugin\MigrateDestinationInterface',
       'process' => 'Drupal\migrate\Plugin\MigrateProcessInterface',
@@ -54,7 +57,7 @@ public function __construct($type, \Traversable $namespaces, CacheBackendInterfa
       'entity_field' => 'Drupal\migrate\Plugin\MigrateEntityDestinationFieldInterface',
     );
     $plugin_interface = isset($plugin_interface_map[$type]) ? $plugin_interface_map[$type] : NULL;
-    parent::__construct("Plugin/migrate/$type", $namespaces, $module_handler, $plugin_interface, $annotation);
+    parent::__construct("Plugin/migrate/$type", $namespaces, $module_handler, $event_dispatcher, $plugin_interface, $annotation);
     $this->alterInfo('migrate_' . $type . '_info');
     $this->setCacheBackend($cache_backend, 'migrate_plugins_' . $type);
   }
diff --git a/core/modules/migrate_drupal/migrate_drupal.services.yml b/core/modules/migrate_drupal/migrate_drupal.services.yml
index 2c8f00c..d6f80a4 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_drupal\Plugin\MigratePluginManager
-    arguments: [load, '@container.namespaces', '@cache.discovery', '@module_handler']
+    arguments: [load, '@container.namespaces', '@cache.discovery', '@module_handler', '@event_dispatcher']
diff --git a/core/modules/quickedit/src/Plugin/InPlaceEditorManager.php b/core/modules/quickedit/src/Plugin/InPlaceEditorManager.php
index 210f675..4446e9d 100644
--- a/core/modules/quickedit/src/Plugin/InPlaceEditorManager.php
+++ b/core/modules/quickedit/src/Plugin/InPlaceEditorManager.php
@@ -10,6 +10,7 @@
 use Drupal\Core\Cache\CacheBackendInterface;
 use Drupal\Core\Extension\ModuleHandlerInterface;
 use Drupal\Core\Plugin\DefaultPluginManager;
+use Symfony\Component\EventDispatcher\EventDispatcherInterface;
 
 /**
  * Provides an in-place editor manager.
@@ -33,9 +34,11 @@ class InPlaceEditorManager extends DefaultPluginManager {
    *   Cache backend instance to use.
    * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
    *   The module handler to invoke the alter hook with.
+   * @param \Symfony\Component\EventDispatcher\EventDispatcherInterface $event_dispatcher
+   *   The event dispatcher.
    */
-  public function __construct(\Traversable $namespaces, CacheBackendInterface $cache_backend, ModuleHandlerInterface $module_handler) {
-    parent::__construct('Plugin/InPlaceEditor', $namespaces, $module_handler, 'Drupal\quickedit\Plugin\InPlaceEditorInterface', 'Drupal\quickedit\Annotation\InPlaceEditor');
+  public function __construct(\Traversable $namespaces, CacheBackendInterface $cache_backend, ModuleHandlerInterface $module_handler, EventDispatcherInterface $event_dispatcher) {
+    parent::__construct('Plugin/InPlaceEditor', $namespaces, $module_handler, $event_dispatcher, 'Drupal\quickedit\Plugin\InPlaceEditorInterface', 'Drupal\quickedit\Annotation\InPlaceEditor');
     $this->alterInfo('quickedit_editor');
     $this->setCacheBackend($cache_backend, 'quickedit:editor');
   }
diff --git a/core/modules/rest/rest.services.yml b/core/modules/rest/rest.services.yml
index c25d692..5e7f54f 100644
--- a/core/modules/rest/rest.services.yml
+++ b/core/modules/rest/rest.services.yml
@@ -1,7 +1,7 @@
 services:
   plugin.manager.rest:
     class: Drupal\rest\Plugin\Type\ResourcePluginManager
-    arguments: ['@container.namespaces', '@cache.discovery', '@module_handler']
+    arguments: ['@container.namespaces', '@cache.discovery', '@module_handler', '@event_dispatcher']
   cache.rest:
     class: Drupal\Core\Cache\CacheBackendInterface
     tags:
diff --git a/core/modules/rest/src/Plugin/Type/ResourcePluginManager.php b/core/modules/rest/src/Plugin/Type/ResourcePluginManager.php
index 97594c4..a477cc7 100644
--- a/core/modules/rest/src/Plugin/Type/ResourcePluginManager.php
+++ b/core/modules/rest/src/Plugin/Type/ResourcePluginManager.php
@@ -10,6 +10,7 @@
 use Drupal\Core\Cache\CacheBackendInterface;
 use Drupal\Core\Extension\ModuleHandlerInterface;
 use Drupal\Core\Plugin\DefaultPluginManager;
+use Symfony\Component\EventDispatcher\EventDispatcherInterface;
 
 /**
  * Manages discovery and instantiation of resource plugins.
@@ -31,9 +32,11 @@ class ResourcePluginManager extends DefaultPluginManager {
    *   Cache backend instance to use.
    * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
    *   The module handler to invoke the alter hook with.
+   * @param \Symfony\Component\EventDispatcher\EventDispatcherInterface $event_dispatcher
+   *   The event dispatcher.
    */
-  public function __construct(\Traversable $namespaces, CacheBackendInterface $cache_backend, ModuleHandlerInterface $module_handler) {
-    parent::__construct('Plugin/rest/resource', $namespaces, $module_handler, 'Drupal\rest\Plugin\ResourceInterface', 'Drupal\rest\Annotation\RestResource');
+  public function __construct(\Traversable $namespaces, CacheBackendInterface $cache_backend, ModuleHandlerInterface $module_handler, EventDispatcherInterface $event_dispatcher) {
+    parent::__construct('Plugin/rest/resource', $namespaces, $module_handler, $event_dispatcher, 'Drupal\rest\Plugin\ResourceInterface', 'Drupal\rest\Annotation\RestResource');
 
     $this->setCacheBackend($cache_backend, 'rest_plugins');
     $this->alterInfo('rest_resource');
diff --git a/core/modules/search/src/SearchPluginManager.php b/core/modules/search/src/SearchPluginManager.php
index bad133a..1709171 100644
--- a/core/modules/search/src/SearchPluginManager.php
+++ b/core/modules/search/src/SearchPluginManager.php
@@ -10,6 +10,7 @@
 use Drupal\Core\Extension\ModuleHandlerInterface;
 use Drupal\Core\Plugin\DefaultPluginManager;
 use Drupal\Core\Cache\CacheBackendInterface;
+use Symfony\Component\EventDispatcher\EventDispatcherInterface;
 
 /**
  * SearchExecute plugin manager.
@@ -26,9 +27,11 @@ class SearchPluginManager extends DefaultPluginManager {
    *   Cache backend instance to use.
    * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
    *   The module handler to invoke the alter hook with.
+   * @param \Symfony\Component\EventDispatcher\EventDispatcherInterface $event_dispatcher
+   *   The event dispatcher.
    */
-  public function __construct(\Traversable $namespaces, CacheBackendInterface $cache_backend, ModuleHandlerInterface $module_handler) {
-    parent::__construct('Plugin/Search', $namespaces, $module_handler, 'Drupal\search\Plugin\SearchInterface', 'Drupal\search\Annotation\SearchPlugin');
+  public function __construct(\Traversable $namespaces, CacheBackendInterface $cache_backend, ModuleHandlerInterface $module_handler, EventDispatcherInterface $event_dispatcher) {
+    parent::__construct('Plugin/Search', $namespaces, $module_handler, $event_dispatcher, 'Drupal\search\Plugin\SearchInterface', 'Drupal\search\Annotation\SearchPlugin');
     $this->setCacheBackend($cache_backend, 'search_plugins');
     $this->alterInfo('search_plugin');
   }
diff --git a/core/modules/system/src/Entity/Menu.php b/core/modules/system/src/Entity/Menu.php
index d44b698..ab81480 100644
--- a/core/modules/system/src/Entity/Menu.php
+++ b/core/modules/system/src/Entity/Menu.php
@@ -64,4 +64,17 @@ public function isLocked() {
     return (bool) $this->locked;
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public static function postDelete(EntityStorageInterface $storage, array $entities) {
+    parent::postDelete($storage, $entities);
+
+    foreach ($entities as $entity) {
+      /** @var \Drupal\block\BlockManagerInterface $block_manager */
+      $block_manager = \Drupal::service('plugin.manager.block');
+      $block_manager->removePlugin('menu_menu_block:' . $entity->id());
+    }
+  }
+
 }
diff --git a/core/modules/system/src/Tests/Plugin/PluginTestBase.php b/core/modules/system/src/Tests/Plugin/PluginTestBase.php
index 3391c73..3f37742 100644
--- a/core/modules/system/src/Tests/Plugin/PluginTestBase.php
+++ b/core/modules/system/src/Tests/Plugin/PluginTestBase.php
@@ -14,6 +14,7 @@
 use Drupal\plugin_test\Plugin\DefaultsTestPluginManager;
 use Drupal\Core\Cache\MemoryBackend;
 use Drupal\Core\Extension\ModuleHandler;
+use Symfony\Component\EventDispatcher\EventDispatcher;
 
 /**
  * Base class for Plugin API unit tests.
@@ -48,7 +49,8 @@ protected function setUp() {
     $this->testPluginManager = new TestPluginManager();
     $this->mockBlockManager = new MockBlockManager();
     $module_handler = new ModuleHandler(array(), new MemoryBackend('plugin'));
-    $this->defaultsTestPluginManager = new DefaultsTestPluginManager($module_handler);
+    $event_dispatcher = new EventDispatcher();
+    $this->defaultsTestPluginManager = new DefaultsTestPluginManager($module_handler, $event_dispatcher);
 
     // The expected plugin definitions within each manager. Several tests assert
     // that these plugins and their definitions are found and returned by the
diff --git a/core/modules/system/tests/modules/condition_test/src/FormController.php b/core/modules/system/tests/modules/condition_test/src/FormController.php
index 1f13755..70429e7 100644
--- a/core/modules/system/tests/modules/condition_test/src/FormController.php
+++ b/core/modules/system/tests/modules/condition_test/src/FormController.php
@@ -34,7 +34,7 @@ public function getFormId() {
    * Constructs a \Drupal\condition_test\FormController object.
    */
   public function __construct() {
-    $manager = new ConditionManager(\Drupal::service('container.namespaces'), \Drupal::cache('discovery'), \Drupal::moduleHandler());
+    $manager = new ConditionManager(\Drupal::service('container.namespaces'), \Drupal::cache('discovery'), \Drupal::moduleHandler(), \Drupal::service('event_dispatcher'));
     $this->condition = $manager->createInstance('node_type');
   }
 
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 bda80fa..347566e 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
@@ -11,6 +11,7 @@
 use Drupal\Component\Plugin\Factory\DefaultFactory;
 use Drupal\Core\Extension\ModuleHandlerInterface;
 use Drupal\Core\Plugin\DefaultPluginManager;
+use Symfony\Component\EventDispatcher\EventDispatcherInterface;
 
 /**
  * Defines a plugin manager used by Plugin API unit tests.
@@ -22,8 +23,10 @@ class DefaultsTestPluginManager extends DefaultPluginManager {
   *
   * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
   *   The module handler.
+  * @param \Symfony\Component\EventDispatcher\EventDispatcherInterface $event_dispatcher
+  *   The event dispatcher.
   */
-  public function __construct(ModuleHandlerInterface $module_handler) {
+  public function __construct(ModuleHandlerInterface $module_handler, EventDispatcherInterface $event_dispatcher) {
     // 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
@@ -31,6 +34,7 @@ public function __construct(ModuleHandlerInterface $module_handler) {
     $this->discovery = new StaticDiscovery();
     $this->factory = new DefaultFactory($this, 'Drupal\Component\Plugin\PluginInspectionInterface');
     $this->moduleHandler = $module_handler;
+    $this->eventDispatcher = $event_dispatcher;
 
     // Specify default values.
     $this->defaults = array(
diff --git a/core/modules/tour/src/TipPluginManager.php b/core/modules/tour/src/TipPluginManager.php
index bcd2c78..d6e04a4 100644
--- a/core/modules/tour/src/TipPluginManager.php
+++ b/core/modules/tour/src/TipPluginManager.php
@@ -10,6 +10,7 @@
 use Drupal\Core\Cache\CacheBackendInterface;
 use Drupal\Core\Extension\ModuleHandlerInterface;
 use Drupal\Core\Plugin\DefaultPluginManager;
+use Symfony\Component\EventDispatcher\EventDispatcherInterface;
 
 /**
  * Provides a plugin manager for tour items.
@@ -31,9 +32,11 @@ class TipPluginManager extends DefaultPluginManager {
    *   Cache backend instance to use.
    * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
    *   The module handler to invoke the alter hook with.
+   * @param \Symfony\Component\EventDispatcher\EventDispatcherInterface $event_dispatcher
+   *   The event dispatcher.
    */
-  public function __construct(\Traversable $namespaces, CacheBackendInterface $cache_backend, ModuleHandlerInterface $module_handler) {
-    parent::__construct('Plugin/tour/tip', $namespaces, $module_handler, 'Drupal\tour\TipPluginInterface', 'Drupal\tour\Annotation\Tip');
+  public function __construct(\Traversable $namespaces, CacheBackendInterface $cache_backend, ModuleHandlerInterface $module_handler, EventDispatcherInterface $event_dispatcher) {
+    parent::__construct('Plugin/tour/tip', $namespaces, $module_handler, $event_dispatcher, 'Drupal\tour\TipPluginInterface', 'Drupal\tour\Annotation\Tip');
 
     $this->alterInfo('tour_tips_info');
     $this->setCacheBackend($cache_backend, 'tour_plugins');
diff --git a/core/modules/views/src/Plugin/ViewsHandlerManager.php b/core/modules/views/src/Plugin/ViewsHandlerManager.php
index 0f334bb..5c6f7a2 100644
--- a/core/modules/views/src/Plugin/ViewsHandlerManager.php
+++ b/core/modules/views/src/Plugin/ViewsHandlerManager.php
@@ -11,9 +11,10 @@
 use Drupal\Core\Cache\CacheBackendInterface;
 use Drupal\Core\Extension\ModuleHandlerInterface;
 use Drupal\Core\Plugin\DefaultPluginManager;
+use Drupal\views\Plugin\views\HandlerBase;
 use Drupal\views\ViewsData;
 use Symfony\Component\DependencyInjection\Container;
-use Drupal\views\Plugin\views\HandlerBase;
+use Symfony\Component\EventDispatcher\EventDispatcherInterface;
 
 /**
  * Plugin type manager for all views handlers.
@@ -50,14 +51,16 @@ class ViewsHandlerManager extends DefaultPluginManager implements FallbackPlugin
    *   Cache backend instance to use.
    * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
    *   The module handler to invoke the alter hook with.
+   * @param \Symfony\Component\EventDispatcher\EventDispatcherInterface $event_dispatcher
+   *   The event dispatcher.
    */
-  public function __construct($handler_type, \Traversable $namespaces, ViewsData $views_data, CacheBackendInterface $cache_backend, ModuleHandlerInterface $module_handler) {
+  public function __construct($handler_type, \Traversable $namespaces, ViewsData $views_data, CacheBackendInterface $cache_backend, ModuleHandlerInterface $module_handler, EventDispatcherInterface $event_dispatcher) {
     $plugin_definition_annotation_name = 'Drupal\views\Annotation\Views' . Container::camelize($handler_type);
     $plugin_interface = 'Drupal\views\Plugin\views\ViewsHandlerInterface';
     if ($handler_type == 'join') {
       $plugin_interface = 'Drupal\views\Plugin\views\join\JoinPluginInterface';
     }
-    parent::__construct("Plugin/views/$handler_type", $namespaces, $module_handler, $plugin_interface, $plugin_definition_annotation_name);
+    parent::__construct("Plugin/views/$handler_type", $namespaces, $module_handler, $event_dispatcher, $plugin_interface, $plugin_definition_annotation_name);
 
     $this->setCacheBackend($cache_backend, "views:$handler_type", array('extension', 'extension:views'));
 
diff --git a/core/modules/views/src/Plugin/ViewsPluginManager.php b/core/modules/views/src/Plugin/ViewsPluginManager.php
index c340ca2..0a99934 100644
--- a/core/modules/views/src/Plugin/ViewsPluginManager.php
+++ b/core/modules/views/src/Plugin/ViewsPluginManager.php
@@ -11,6 +11,7 @@
 use Drupal\Core\Extension\ModuleHandlerInterface;
 use Drupal\Core\Plugin\DefaultPluginManager;
 use Symfony\Component\DependencyInjection\Container;
+use Symfony\Component\EventDispatcher\EventDispatcherInterface;
 
 /**
  * Plugin type manager for all views plugins.
@@ -31,10 +32,12 @@ class ViewsPluginManager extends DefaultPluginManager {
    *   Cache backend instance to use.
    * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
    *   The module handler to invoke the alter hook with.
+   * @param \Symfony\Component\EventDispatcher\EventDispatcherInterface $event_dispatcher
+   *   The event dispatcher.
    */
-  public function __construct($type, \Traversable $namespaces, CacheBackendInterface $cache_backend, ModuleHandlerInterface $module_handler) {
+  public function __construct($type, \Traversable $namespaces, CacheBackendInterface $cache_backend, ModuleHandlerInterface $module_handler, EventDispatcherInterface $event_dispatcher) {
     $plugin_definition_annotation_name = 'Drupal\views\Annotation\Views' . Container::camelize($type);
-    parent::__construct("Plugin/views/$type", $namespaces, $module_handler, 'Drupal\views\Plugin\views\ViewsPluginInterface', $plugin_definition_annotation_name);
+    parent::__construct("Plugin/views/$type", $namespaces, $module_handler, $event_dispatcher, 'Drupal\views\Plugin\views\ViewsPluginInterface', $plugin_definition_annotation_name);
 
     $this->defaults += array(
       'parent' => 'parent',
diff --git a/core/modules/views/views.services.yml b/core/modules/views/views.services.yml
index b66568f..92059dd 100644
--- a/core/modules/views/views.services.yml
+++ b/core/modules/views/views.services.yml
@@ -1,61 +1,61 @@
 services:
   plugin.manager.views.access:
     class: Drupal\views\Plugin\ViewsPluginManager
-    arguments: [access, '@container.namespaces', '@cache.discovery', '@module_handler']
+    arguments: [access, '@container.namespaces', '@cache.discovery', '@module_handler', '@event_dispatcher']
   plugin.manager.views.area:
     class: Drupal\views\Plugin\ViewsHandlerManager
-    arguments: [area, '@container.namespaces', '@views.views_data', '@cache.discovery', '@module_handler']
+    arguments: [area, '@container.namespaces', '@views.views_data', '@cache.discovery', '@module_handler', '@event_dispatcher']
   plugin.manager.views.argument:
     class: Drupal\views\Plugin\ViewsHandlerManager
-    arguments: [argument, '@container.namespaces', '@views.views_data', '@cache.discovery', '@module_handler']
+    arguments: [argument, '@container.namespaces', '@views.views_data', '@cache.discovery', '@module_handler', '@event_dispatcher']
   plugin.manager.views.argument_default:
     class: Drupal\views\Plugin\ViewsPluginManager
-    arguments: [argument_default, '@container.namespaces', '@cache.discovery', '@module_handler']
+    arguments: [argument_default, '@container.namespaces', '@cache.discovery', '@module_handler', '@event_dispatcher']
   plugin.manager.views.argument_validator:
     class: Drupal\views\Plugin\ViewsPluginManager
-    arguments: [argument_validator, '@container.namespaces', '@cache.discovery', '@module_handler']
+    arguments: [argument_validator, '@container.namespaces', '@cache.discovery', '@module_handler', '@event_dispatcher']
   plugin.manager.views.cache:
     class: Drupal\views\Plugin\ViewsPluginManager
-    arguments: [cache, '@container.namespaces', '@cache.discovery', '@module_handler']
+    arguments: [cache, '@container.namespaces', '@cache.discovery', '@module_handler', '@event_dispatcher']
   plugin.manager.views.display_extender:
     class: Drupal\views\Plugin\ViewsPluginManager
-    arguments: [display_extender, '@container.namespaces', '@cache.discovery', '@module_handler']
+    arguments: [display_extender, '@container.namespaces', '@cache.discovery', '@module_handler', '@event_dispatcher']
   plugin.manager.views.display:
     class: Drupal\views\Plugin\ViewsPluginManager
-    arguments: [display, '@container.namespaces', '@cache.discovery', '@module_handler']
+    arguments: [display, '@container.namespaces', '@cache.discovery', '@module_handler', '@event_dispatcher']
   plugin.manager.views.exposed_form:
     class: Drupal\views\Plugin\ViewsPluginManager
-    arguments: [exposed_form, '@container.namespaces', '@cache.discovery', '@module_handler']
+    arguments: [exposed_form, '@container.namespaces', '@cache.discovery', '@module_handler', '@event_dispatcher']
   plugin.manager.views.field:
     class: Drupal\views\Plugin\ViewsHandlerManager
-    arguments: [field, '@container.namespaces', '@views.views_data', '@cache.discovery', '@module_handler']
+    arguments: [field, '@container.namespaces', '@views.views_data', '@cache.discovery', '@module_handler', '@event_dispatcher']
   plugin.manager.views.filter:
     class: Drupal\views\Plugin\ViewsHandlerManager
-    arguments: [filter, '@container.namespaces', '@views.views_data', '@cache.discovery', '@module_handler']
+    arguments: [filter, '@container.namespaces', '@views.views_data', '@cache.discovery', '@module_handler', '@event_dispatcher']
   plugin.manager.views.join:
     class: Drupal\views\Plugin\ViewsHandlerManager
-    arguments: [join, '@container.namespaces', '@views.views_data', '@cache.discovery', '@module_handler']
+    arguments: [join, '@container.namespaces', '@views.views_data', '@cache.discovery', '@module_handler', '@event_dispatcher']
   plugin.manager.views.pager:
     class: Drupal\views\Plugin\ViewsPluginManager
-    arguments: [pager, '@container.namespaces', '@cache.discovery', '@module_handler']
+    arguments: [pager, '@container.namespaces', '@cache.discovery', '@module_handler', '@event_dispatcher']
   plugin.manager.views.query:
     class: Drupal\views\Plugin\ViewsPluginManager
-    arguments: [query, '@container.namespaces', '@cache.discovery', '@module_handler']
+    arguments: [query, '@container.namespaces', '@cache.discovery', '@module_handler', '@event_dispatcher']
   plugin.manager.views.relationship:
     class: Drupal\views\Plugin\ViewsHandlerManager
-    arguments: [relationship, '@container.namespaces', '@views.views_data', '@cache.discovery', '@module_handler']
+    arguments: [relationship, '@container.namespaces', '@views.views_data', '@cache.discovery', '@module_handler', '@event_dispatcher']
   plugin.manager.views.row:
     class: Drupal\views\Plugin\ViewsPluginManager
-    arguments: [row, '@container.namespaces', '@cache.discovery', '@module_handler']
+    arguments: [row, '@container.namespaces', '@cache.discovery', '@module_handler', '@event_dispatcher']
   plugin.manager.views.sort:
     class: Drupal\views\Plugin\ViewsHandlerManager
-    arguments: [sort, '@container.namespaces', '@views.views_data', '@cache.discovery', '@module_handler']
+    arguments: [sort, '@container.namespaces', '@views.views_data', '@cache.discovery', '@module_handler', '@event_dispatcher']
   plugin.manager.views.style:
     class: Drupal\views\Plugin\ViewsPluginManager
-    arguments: [style, '@container.namespaces', '@cache.discovery', '@module_handler']
+    arguments: [style, '@container.namespaces', '@cache.discovery', '@module_handler', '@event_dispatcher']
   plugin.manager.views.wizard:
     class: Drupal\views\Plugin\ViewsPluginManager
-    arguments: [wizard, '@container.namespaces', '@cache.discovery', '@module_handler']
+    arguments: [wizard, '@container.namespaces', '@cache.discovery', '@module_handler', '@event_dispatcher']
   views.views_data:
     class: Drupal\views\ViewsData
     arguments: ['@cache.discovery', '@config.factory', '@module_handler', '@language_manager']
diff --git a/core/tests/Drupal/Tests/Core/Block/BlockManagerTest.php b/core/tests/Drupal/Tests/Core/Block/BlockManagerTest.php
new file mode 100644
index 0000000..bb6bd59
--- /dev/null
+++ b/core/tests/Drupal/Tests/Core/Block/BlockManagerTest.php
@@ -0,0 +1,47 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Tests\Core\Block\BlockManagerTest.
+ */
+
+namespace Drupal\Tests\Core\Block;
+
+use Drupal\Core\Plugin\Event\PluginRemovalEvent;
+use Drupal\Core\Plugin\PluginEvents;
+use Drupal\Tests\UnitTestCase;
+use Symfony\Component\EventDispatcher\EventDispatcher;
+
+/**
+ * Tests the block plugin manager.
+ *
+ * @group block
+ *
+ * @coversDefaultClass \Drupal\block\Plugin\BlockManager
+ */
+class BlockManagerTest extends UnitTestCase {
+
+  /**
+   * Tests the reaction when firing block plugin events.
+   *
+   * @covers ::getSubscribedEvents
+   * @covers ::blockPluginRemoved
+   */
+  public function testBlockPluginEvents() {
+    $event_dispatcher = new EventDispatcher();
+
+    $block_manager = $this->getMockBuilder('Drupal\Core\Block\BlockManager')
+      ->disableOriginalConstructor()
+      ->setMethods(array('clearCachedDefinitions'))
+      ->getMock();
+
+    $block_manager->expects($this->once())
+      ->method('clearCachedDefinitions');
+
+    $event_dispatcher->addSubscriber($block_manager);
+    $event = new PluginRemovalEvent('plugin_block', 'test_plugin_id');
+
+    $event_dispatcher->dispatch(PluginEvents::REMOVAL, $event);
+  }
+
+}
diff --git a/core/tests/Drupal/Tests/Core/Entity/EntityManagerTest.php b/core/tests/Drupal/Tests/Core/Entity/EntityManagerTest.php
index fa3678c..4440fa3 100644
--- a/core/tests/Drupal/Tests/Core/Entity/EntityManagerTest.php
+++ b/core/tests/Drupal/Tests/Core/Entity/EntityManagerTest.php
@@ -101,6 +101,13 @@ class EntityManagerTest extends UnitTestCase {
   protected $installedDefinitions;
 
   /**
+   * The mocked event dispatcher.
+   *
+   * @var \Symfony\Component\EventDispatcher\EventDispatcherInterface
+   */
+  protected $eventDispatcher;
+
+  /**
    * {@inheritdoc}
    */
   protected function setUp() {
@@ -111,6 +118,7 @@ protected function setUp() {
       ->method('getImplementations')
       ->with('entity_type_build')
       ->will($this->returnValue(array()));
+    $this->eventDispatcher = $this->getMock('Symfony\Component\EventDispatcher\EventDispatcherInterface');
 
     $this->cache = $this->getMock('Drupal\Core\Cache\CacheBackendInterface');
 
@@ -167,7 +175,7 @@ protected function setUpEntityManager($definitions = array()) {
       ->method('getDefinitions')
       ->will($this->returnValue($definitions));
 
-    $this->entityManager = new TestEntityManager(new \ArrayObject(), $this->moduleHandler, $this->cache, $this->languageManager, $this->translationManager, $this->getClassResolverStub(), $this->typedDataManager, $this->installedDefinitions);
+    $this->entityManager = new TestEntityManager(new \ArrayObject(), $this->moduleHandler, $this->eventDispatcher, $this->cache, $this->languageManager, $this->translationManager, $this->getClassResolverStub(), $this->typedDataManager, $this->installedDefinitions);
     $this->entityManager->setContainer($this->container);
     $this->entityManager->setDiscovery($this->discovery);
   }
@@ -183,10 +191,10 @@ public function testClearCachedDefinitions() {
     $this->cache->expects($this->at(0))
       ->method('deleteTags')
       ->with(array('entity_types'));
-    $this->cache->expects($this->at(1))
+    $this->cache->expects($this->at(2))
       ->method('deleteTags')
       ->with(array('entity_bundles'));
-    $this->cache->expects($this->at(2))
+    $this->cache->expects($this->at(3))
       ->method('deleteTags')
       ->with(array('entity_field_info'));
 
diff --git a/core/tests/Drupal/Tests/Core/Field/BaseFieldDefinitionTestBase.php b/core/tests/Drupal/Tests/Core/Field/BaseFieldDefinitionTestBase.php
index 1fffe45..585fc30 100644
--- a/core/tests/Drupal/Tests/Core/Field/BaseFieldDefinitionTestBase.php
+++ b/core/tests/Drupal/Tests/Core/Field/BaseFieldDefinitionTestBase.php
@@ -40,10 +40,12 @@ protected function setUp() {
       ->method('moduleExists')
       ->with($module_name)
       ->will($this->returnValue(TRUE));
+    $event_dispatcher = $this->getMock('Symfony\Component\EventDispatcher\EventDispatcherInterface');
     $plugin_manager = new FieldTypePluginManager(
       $namespaces,
       $this->getMock('Drupal\Core\Cache\CacheBackendInterface'),
-      $module_handler
+      $module_handler,
+      $event_dispatcher
     );
 
     $container = new ContainerBuilder();
diff --git a/core/tests/Drupal/Tests/Core/Mail/MailManagerTest.php b/core/tests/Drupal/Tests/Core/Mail/MailManagerTest.php
index 7d19b8a..3fb9be6 100644
--- a/core/tests/Drupal/Tests/Core/Mail/MailManagerTest.php
+++ b/core/tests/Drupal/Tests/Core/Mail/MailManagerTest.php
@@ -52,6 +52,13 @@ class MailManagerTest extends UnitTestCase {
   protected $mailManager;
 
   /**
+   * The mocked event dispatcher.
+   *
+   * @var \Symfony\Component\EventDispatcher\EventDispatcherInterface
+   */
+  protected $eventDispatcher;
+
+  /**
    * A list of mail plugin definitions.
    *
    * @var array
@@ -76,6 +83,7 @@ protected function setUp() {
     $this->cache = $this->getMock('Drupal\Core\Cache\CacheBackendInterface');
 
     $this->moduleHandler = $this->getMock('Drupal\Core\Extension\ModuleHandlerInterface');
+    $this->eventDispatcher = $this->getMock('Symfony\Component\EventDispatcher\EventDispatcherInterface');
 
     // Mock a Discovery object to replace AnnotationClassDiscovery.
     $this->discovery = $this->getMock('Drupal\Component\Plugin\Discovery\DiscoveryInterface');
@@ -97,7 +105,7 @@ protected function setUpMailManager($interface = array()) {
     $logger_factory = $this->getMock('\Drupal\Core\Logger\LoggerChannelFactoryInterface');
     $string_translation = $this->getStringTranslationStub();
     // Construct the manager object and override its discovery.
-    $this->mailManager = new TestMailManager(new \ArrayObject(), $this->cache, $this->moduleHandler, $this->configFactory, $logger_factory, $string_translation);
+    $this->mailManager = new TestMailManager(new \ArrayObject(), $this->cache, $this->moduleHandler, $this->eventDispatcher, $this->configFactory, $logger_factory, $string_translation);
     $this->mailManager->setDiscovery($this->discovery);
   }
 
diff --git a/core/tests/Drupal/Tests/Core/Menu/LocalActionManagerTest.php b/core/tests/Drupal/Tests/Core/Menu/LocalActionManagerTest.php
index 1942fc3..5d8f80d 100644
--- a/core/tests/Drupal/Tests/Core/Menu/LocalActionManagerTest.php
+++ b/core/tests/Drupal/Tests/Core/Menu/LocalActionManagerTest.php
@@ -17,6 +17,7 @@
 use Drupal\Core\Routing\RouteProviderInterface;
 use Drupal\Core\Session\AccountInterface;
 use Drupal\Tests\UnitTestCase;
+use Symfony\Component\EventDispatcher\EventDispatcherInterface;
 use Symfony\Component\HttpFoundation\Request;
 use Symfony\Component\HttpFoundation\RequestStack;
 use Symfony\Component\HttpKernel\Controller\ControllerResolverInterface;
@@ -91,6 +92,13 @@ class LocalActionManagerTest extends UnitTestCase {
   protected $discovery;
 
   /**
+   * The mocked event dispatcher.
+   *
+   * @var \Symfony\Component\EventDispatcher\EventDispatcherInterface
+   */
+  protected $eventDispatcher;
+
+  /**
    * The tested local action manager
    *
    * @var \Drupal\Tests\Core\Menu\TestLocalActionManager
@@ -105,6 +113,7 @@ protected function setUp() {
     $this->request = $this->getMock('Symfony\Component\HttpFoundation\Request');
     $this->routeProvider = $this->getMock('Drupal\Core\Routing\RouteProviderInterface');
     $this->moduleHandler = $this->getMock('Drupal\Core\Extension\ModuleHandlerInterface');
+    $this->eventDispatcher = $this->getMock('Symfony\Component\EventDispatcher\EventDispatcherInterface');
     $this->cacheBackend = $this->getMock('Drupal\Core\Cache\CacheBackendInterface');
 
     $this->accessManager = $this->getMock('Drupal\Core\Access\AccessManagerInterface');
@@ -115,7 +124,7 @@ protected function setUp() {
     $this->discovery = $this->getMock('Drupal\Component\Plugin\Discovery\DiscoveryInterface');
     $this->factory = $this->getMock('Drupal\Component\Plugin\Factory\FactoryInterface');
 
-    $this->localActionManager = new TestLocalActionManager($this->controllerResolver, $this->request, $this->routeProvider, $this->moduleHandler, $this->cacheBackend, $this->accessManager, $this->account, $this->discovery, $this->factory);
+    $this->localActionManager = new TestLocalActionManager($this->controllerResolver, $this->request, $this->routeProvider, $this->moduleHandler, $this->eventDispatcher,$this->cacheBackend, $this->accessManager, $this->account, $this->discovery, $this->factory);
   }
 
   /**
@@ -344,7 +353,7 @@ public function getActionsForRouteProvider() {
 
 class TestLocalActionManager extends LocalActionManager {
 
-  public function __construct(ControllerResolverInterface $controller_resolver, Request $request, RouteProviderInterface $route_provider, ModuleHandlerInterface $module_handler, CacheBackendInterface $cache_backend, AccessManagerInterface $access_manager, AccountInterface $account, DiscoveryInterface $discovery, FactoryInterface $factory) {
+  public function __construct(ControllerResolverInterface $controller_resolver, Request $request, RouteProviderInterface $route_provider, ModuleHandlerInterface $module_handler, EventDispatcherInterface $event_dispatcher, CacheBackendInterface $cache_backend, AccessManagerInterface $access_manager, AccountInterface $account, DiscoveryInterface $discovery, FactoryInterface $factory) {
     $this->discovery = $discovery;
     $this->factory = $factory;
     $this->routeProvider = $route_provider;
@@ -354,6 +363,7 @@ public function __construct(ControllerResolverInterface $controller_resolver, Re
     $this->requestStack = new RequestStack();
     $this->requestStack->push($request);
     $this->moduleHandler = $module_handler;
+    $this->eventDispatcher = $event_dispatcher;
     $this->alterInfo('menu_local_actions');
     $this->setCacheBackend($cache_backend, 'local_action_plugins', array('local_action'));
   }
diff --git a/core/tests/Drupal/Tests/Core/Plugin/DefaultPluginManagerTest.php b/core/tests/Drupal/Tests/Core/Plugin/DefaultPluginManagerTest.php
index 9d7f08f..642d06e 100644
--- a/core/tests/Drupal/Tests/Core/Plugin/DefaultPluginManagerTest.php
+++ b/core/tests/Drupal/Tests/Core/Plugin/DefaultPluginManagerTest.php
@@ -7,6 +7,8 @@
 
 namespace Drupal\Tests\Core\Plugin;
 
+use Drupal\Core\Plugin\Event\PluginRemovalEvent;
+use Drupal\Core\Plugin\PluginEvents;
 use Drupal\Tests\UnitTestCase;
 
 /**
@@ -77,8 +79,9 @@ public function testDefaultPluginManagerWithDisabledModule() {
       ->method('moduleExists')
       ->with('disabled_module')
       ->will($this->returnValue(FALSE));
+    $event_dispatcher = $this->getMock('Symfony\Component\EventDispatcher\EventDispatcherInterface');
 
-    $plugin_manager = new TestPluginManager($this->namespaces, $definitions, $module_handler, 'test_alter_hook', '\Drupal\plugin_test\Plugin\plugin_test\fruit\FruitInterface');
+    $plugin_manager = new TestPluginManager($this->namespaces, $definitions, $module_handler, 'test_alter_hook', $event_dispatcher, '\Drupal\plugin_test\Plugin\plugin_test\fruit\FruitInterface');
 
     $this->assertEmpty($plugin_manager->getDefinition('cherry', FALSE), 'Plugin information of a disabled module is not available');
   }
@@ -102,8 +105,9 @@ public function testDefaultPluginManagerWithObjects() {
       ->method('moduleExists')
       ->with('disabled_module')
       ->will($this->returnValue(FALSE));
+    $event_dispatcher = $this->getMock('Symfony\Component\EventDispatcher\EventDispatcherInterface');
 
-    $plugin_manager = new TestPluginManager($this->namespaces, $definitions, $module_handler, 'test_alter_hook', '\Drupal\plugin_test\Plugin\plugin_test\fruit\FruitInterface');
+    $plugin_manager = new TestPluginManager($this->namespaces, $definitions, $module_handler, 'test_alter_hook', $event_dispatcher, '\Drupal\plugin_test\Plugin\plugin_test\fruit\FruitInterface');
 
     $this->assertEmpty($plugin_manager->getDefinition('cherry', FALSE), 'Plugin information is available');
   }
@@ -112,7 +116,8 @@ public function testDefaultPluginManagerWithObjects() {
    * Tests the plugin manager with no cache and altering.
    */
   public function testDefaultPluginManager() {
-    $plugin_manager = new TestPluginManager($this->namespaces, $this->expectedDefinitions, NULL, NULL, '\Drupal\plugin_test\Plugin\plugin_test\fruit\FruitInterface');
+    $event_dispatcher = $this->getMock('Symfony\Component\EventDispatcher\EventDispatcherInterface');
+    $plugin_manager = new TestPluginManager($this->namespaces, $this->expectedDefinitions, NULL, NULL, $event_dispatcher, '\Drupal\plugin_test\Plugin\plugin_test\fruit\FruitInterface');
     $this->assertEquals($this->expectedDefinitions, $plugin_manager->getDefinitions());
     $this->assertEquals($this->expectedDefinitions['banana'], $plugin_manager->getDefinition('banana'));
   }
@@ -130,8 +135,9 @@ public function testDefaultPluginManagerWithAlter() {
     $module_handler->expects($this->once())
       ->method('alter')
       ->with($this->equalTo($alter_hook_name), $this->equalTo($this->expectedDefinitions));
+    $event_dispatcher = $this->getMock('Symfony\Component\EventDispatcher\EventDispatcherInterface');
 
-    $plugin_manager = new TestPluginManager($this->namespaces, $this->expectedDefinitions, $module_handler, $alter_hook_name, '\Drupal\plugin_test\Plugin\plugin_test\fruit\FruitInterface');
+    $plugin_manager = new TestPluginManager($this->namespaces, $this->expectedDefinitions, $module_handler, $alter_hook_name, $event_dispatcher, '\Drupal\plugin_test\Plugin\plugin_test\fruit\FruitInterface');
 
     $this->assertEquals($this->expectedDefinitions, $plugin_manager->getDefinitions());
     $this->assertEquals($this->expectedDefinitions['banana'], $plugin_manager->getDefinition('banana'));
@@ -154,8 +160,9 @@ public function testDefaultPluginManagerWithEmptyCache() {
       ->expects($this->once())
       ->method('set')
       ->with($cid, $this->expectedDefinitions);
+    $event_dispatcher = $this->getMock('Symfony\Component\EventDispatcher\EventDispatcherInterface');
 
-    $plugin_manager = new TestPluginManager($this->namespaces, $this->expectedDefinitions, NULL, NULL, '\Drupal\plugin_test\Plugin\plugin_test\fruit\FruitInterface');
+    $plugin_manager = new TestPluginManager($this->namespaces, $this->expectedDefinitions, NULL, NULL, $event_dispatcher, '\Drupal\plugin_test\Plugin\plugin_test\fruit\FruitInterface');
     $plugin_manager->setCacheBackend($cache_backend, $cid);
 
     $this->assertEquals($this->expectedDefinitions, $plugin_manager->getDefinitions());
@@ -178,14 +185,50 @@ public function testDefaultPluginManagerWithFilledCache() {
     $cache_backend
       ->expects($this->never())
       ->method('set');
+    $event_dispatcher = $this->getMock('Symfony\Component\EventDispatcher\EventDispatcherInterface');
 
-    $plugin_manager = new TestPluginManager($this->namespaces, $this->expectedDefinitions, NULL, NULL, '\Drupal\plugin_test\Plugin\plugin_test\fruit\FruitInterface');
+    $plugin_manager = new TestPluginManager($this->namespaces, $this->expectedDefinitions, NULL, NULL, $event_dispatcher, '\Drupal\plugin_test\Plugin\plugin_test\fruit\FruitInterface');
     $plugin_manager->setCacheBackend($cache_backend, $cid);
 
     $this->assertEquals($this->expectedDefinitions, $plugin_manager->getDefinitions());
   }
 
   /**
+   * Tests the plugin manager cache clear with filled cache and removed plugins.
+   */
+  public function testCacheClearWithFilledCacheAndRemovedPlugins() {
+    $cid = $this->randomMachineName();
+    $cache_backend = $this->getMockBuilder('Drupal\Core\Cache\MemoryBackend')
+      ->disableOriginalConstructor()
+      ->getMock();
+    $cache_backend
+      ->expects($this->once())
+      ->method('get')
+      ->with($cid)
+      ->will($this->returnValue((object) array('data' => $this->expectedDefinitions)));
+    $cache_backend
+      ->expects($this->never())
+      ->method('set');
+    $event_dispatcher = $this->getMock('Symfony\Component\EventDispatcher\EventDispatcherInterface');
+
+    $plugin_manager = new TestPluginManager($this->namespaces, $this->expectedDefinitions, NULL, NULL, $event_dispatcher, '\Drupal\plugin_test\Plugin\plugin_test\fruit\FruitInterface');
+    $plugin_manager->setCacheBackend($cache_backend, $cid);
+    $plugin_manager->setSubDir('Plugin/test/example');
+
+    // Remove the available plugins and ensure that the removePlugin() method is
+    // called automatically.
+    $static_discovery = $plugin_manager->getDiscovery();
+    $static_discovery->deleteDefinition('apple');
+
+    $plugin_event = new PluginRemovalEvent('plugin_test_example', 'apple');
+    $event_dispatcher->expects($this->once())
+      ->method('dispatch')
+      ->with(PluginEvents::REMOVAL, $plugin_event);
+
+    $plugin_manager->clearCachedDefinitions();
+  }
+
+  /**
    * Tests the plugin manager cache clear with tags.
    */
   public function testCacheClearWithTags() {
@@ -202,8 +245,9 @@ public function testCacheClearWithTags() {
       ->method('deleteMultiple');
 
     $this->getContainerWithCacheBins($cache_backend);
+    $event_dispatcher = $this->getMock('Symfony\Component\EventDispatcher\EventDispatcherInterface');
 
-    $plugin_manager = new TestPluginManager($this->namespaces, $this->expectedDefinitions, NULL, NULL, '\Drupal\plugin_test\Plugin\plugin_test\fruit\FruitInterface');
+    $plugin_manager = new TestPluginManager($this->namespaces, $this->expectedDefinitions, NULL, NULL, $event_dispatcher, '\Drupal\plugin_test\Plugin\plugin_test\fruit\FruitInterface');
     $plugin_manager->setCacheBackend($cache_backend, $cid, array('tag'));
 
     $plugin_manager->clearCachedDefinitions();
@@ -216,7 +260,8 @@ public function testCacheClearWithTags() {
    * @covers ::enforcePluginInterface
    */
   public function testCreateInstanceWithJustValidInterfaces() {
-    $plugin_manager = new TestPluginManager($this->namespaces, $this->expectedDefinitions, NULL, NULL, '\Drupal\plugin_test\Plugin\plugin_test\fruit\FruitInterface');
+    $event_dispatcher = $this->getMock('Symfony\Component\EventDispatcher\EventDispatcherInterface');
+    $plugin_manager = new TestPluginManager($this->namespaces, $this->expectedDefinitions, NULL, NULL, $event_dispatcher, '\Drupal\plugin_test\Plugin\plugin_test\fruit\FruitInterface');
 
     foreach ($this->expectedDefinitions as $plugin_id => $definition) {
       $plugin_manager->createInstance($plugin_id);
@@ -239,6 +284,7 @@ public function testCreateInstanceWithInvalidInterfaces() {
       ->method('moduleExists')
       ->with('plugin_test')
       ->willReturn(TRUE);
+    $event_dispatcher = $this->getMock('Symfony\Component\EventDispatcher\EventDispatcherInterface');
 
     $this->expectedDefinitions['kale'] = array(
       'id' => 'kale',
@@ -250,7 +296,7 @@ public function testCreateInstanceWithInvalidInterfaces() {
     $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 = new TestPluginManager($this->namespaces, $this->expectedDefinitions, $module_handler, NULL, $event_dispatcher, '\Drupal\plugin_test\Plugin\plugin_test\fruit\FruitInterface');
     $plugin_manager->createInstance('kale');
   }
 
@@ -282,4 +328,22 @@ public function testGetDefinitionsWithoutRequiredInterface() {
     $plugin_manager->getDefinitions();
   }
 
+  /**
+   * Tests the removePlugin() method.
+   *
+   * @covers ::removePlugin
+   */
+  public function testRemovePlugin() {
+    $event_dispatcher = $this->getMock('Symfony\Component\EventDispatcher\EventDispatcherInterface');
+    $plugin_manager = new TestPluginManager($this->namespaces, $this->expectedDefinitions, NULL, NULL, $event_dispatcher, '\Drupal\plugin_test\Plugin\plugin_test\fruit\FruitInterface');
+    $plugin_manager->setSubDir('Plugin/test/Example');
+
+    $plugin_event = new PluginRemovalEvent('plugin_test_example', 'test_id');
+    $event_dispatcher->expects($this->once())
+      ->method('dispatch')
+      ->with(PluginEvents::REMOVAL, $plugin_event);
+
+    $plugin_manager->removePlugin('test_id');
+  }
+
 }
diff --git a/core/tests/Drupal/Tests/Core/Plugin/TestPluginManager.php b/core/tests/Drupal/Tests/Core/Plugin/TestPluginManager.php
index c1c2d7f..e1a75d1 100644
--- a/core/tests/Drupal/Tests/Core/Plugin/TestPluginManager.php
+++ b/core/tests/Drupal/Tests/Core/Plugin/TestPluginManager.php
@@ -11,6 +11,7 @@
 use Drupal\Component\Plugin\Factory\DefaultFactory;
 use Drupal\Core\Extension\ModuleHandlerInterface;
 use Drupal\Core\Plugin\DefaultPluginManager;
+use Symfony\Component\EventDispatcher\EventDispatcherInterface;
 
 /**
  * A plugin manager for condition plugins.
@@ -31,8 +32,10 @@ class TestPluginManager extends DefaultPluginManager {
    *   (optional) Name of the alter hook.
    * @param string $interface
    *   (optional) The interface required for the plugins.
+   * @param \Symfony\Component\EventDispatcher\EventDispatcherInterface $event_dispatcher
+   *   (optional) The event dispatcher.
    */
-  public function __construct(\Traversable $namespaces, array $definitions, ModuleHandlerInterface $module_handler = NULL, $alter_hook = NULL, $interface = NULL) {
+  public function __construct(\Traversable $namespaces, array $definitions, ModuleHandlerInterface $module_handler = NULL, $alter_hook = NULL, EventDispatcherInterface $event_dispatcher = 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,10 +49,24 @@ public function __construct(\Traversable $namespaces, array $definitions, Module
     }
 
     $this->moduleHandler = $module_handler;
+    $this->eventDispatcher = $event_dispatcher;
 
     if ($alter_hook) {
       $this->alterInfo($alter_hook);
     }
   }
 
+  /**
+   * The plugin discovery.
+   *
+   * @return \Drupal\Component\Plugin\Discovery\StaticDiscovery
+   */
+  public function getDiscovery() {
+    return $this->discovery;
+  }
+
+  public function setSubDir($sub_dir) {
+    $this->subdir = $sub_dir;
+  }
+
 }
diff --git a/core/tests/Drupal/Tests/Core/Render/ElementInfoManagerTest.php b/core/tests/Drupal/Tests/Core/Render/ElementInfoManagerTest.php
index 42c9f3b..35ae0dc 100644
--- a/core/tests/Drupal/Tests/Core/Render/ElementInfoManagerTest.php
+++ b/core/tests/Drupal/Tests/Core/Render/ElementInfoManagerTest.php
@@ -31,6 +31,13 @@ class ElementInfoManagerTest extends UnitTestCase {
   protected $cache;
 
   /**
+   * The mocked event dispatcher.
+   *
+   * @var \Symfony\Component\EventDispatcher\EventDispatcherInterface
+   */
+  protected $eventDispatcher;
+
+  /**
    * The mocked module handler.
    *
    * @var \Drupal\Core\Extension\ModuleHandlerInterface|\PHPUnit_Framework_MockObject_MockObject
@@ -45,8 +52,9 @@ class ElementInfoManagerTest extends UnitTestCase {
   protected function setUp() {
     $this->cache = $this->getMock('Drupal\Core\Cache\CacheBackendInterface');
     $this->moduleHandler = $this->getMock('Drupal\Core\Extension\ModuleHandlerInterface');
+    $this->eventDispatcher = $this->getMock('Symfony\Component\EventDispatcher\EventDispatcherInterface');
 
-    $this->elementInfo = new ElementInfoManager(new \ArrayObject(), $this->cache, $this->moduleHandler);
+    $this->elementInfo = new ElementInfoManager(new \ArrayObject(), $this->cache, $this->moduleHandler, $this->eventDispatcher);
   }
 
   /**
@@ -152,7 +160,7 @@ public function testGetInfoElementPlugin($plugin_class, $expected_info) {
       ));
 
     $element_info = $this->getMockBuilder('Drupal\Core\Render\ElementInfoManager')
-      ->setConstructorArgs(array(new \ArrayObject(), $this->cache, $this->moduleHandler))
+      ->setConstructorArgs(array(new \ArrayObject(), $this->cache, $this->moduleHandler, $this->eventDispatcher))
       ->setMethods(array('getDefinitions', 'createInstance'))
       ->getMock();
     $element_info->expects($this->once())
