diff --git a/core/includes/language.inc b/core/includes/language.inc
index 5f7d823..af45498 100644
--- a/core/includes/language.inc
+++ b/core/includes/language.inc
@@ -8,6 +8,8 @@
  */
 
 use Drupal\Core\Language\Language;
+use Drupal\block\BlockPluginEvents;
+use Symfony\Component\EventDispatcher\GenericEvent;
 
 /**
  * No language negotiation. The default language is used.
@@ -193,6 +195,13 @@ function language_types_get_configurable() {
 function language_types_disable($types) {
   $configurable = language_types_get_configurable();
   config('system.language.types')->set('configurable', array_diff($configurable, $types))->save();
+  foreach ($types as $type) {
+    // Inform the block plugin system that a language has been deleted.
+    if (Drupal::moduleHandler()->moduleExists('block')) {
+      $event = new GenericEvent('language_block:' . $type);
+      Drupal::service('event_dispatcher')->dispatch(BlockPluginEvents::PERMANENTLY_UNAVAILABLE, $event);
+    }
+  }
 }
 
 /**
diff --git a/core/modules/aggregator/aggregator.module b/core/modules/aggregator/aggregator.module
index f7a908a..bca5322 100644
--- a/core/modules/aggregator/aggregator.module
+++ b/core/modules/aggregator/aggregator.module
@@ -6,7 +6,9 @@
  */
 
 use Drupal\aggregator\Plugin\Core\Entity\Feed;
+use Drupal\block\BlockPluginEvents;
 use Drupal\Component\Plugin\Exception\PluginException;
+use Symfony\Component\EventDispatcher\GenericEvent;
 
 /**
  * Denotes that a feed's items should never expire.
@@ -333,9 +335,8 @@ function aggregator_save_category($edit) {
         ->execute();
       // Make sure there is no active block for this category.
       if (Drupal::moduleHandler()->moduleExists('block')) {
-        foreach (entity_load_multiple_by_properties('block', array('plugin' => 'aggregator_category_block:' . $edit['cid'])) as $block) {
-          $block->delete();
-        }
+        $event = new GenericEvent('aggregator_category_block:' . $edit['cid']);
+        \Drupal::service('event_dispatcher')->dispatch(BlockPluginEvents::DISAPPEAR_PERMANENT, $event);
       }
       $edit['title'] = '';
       $op = 'delete';
diff --git a/core/modules/aggregator/lib/Drupal/aggregator/Plugin/Core/Entity/Feed.php b/core/modules/aggregator/lib/Drupal/aggregator/Plugin/Core/Entity/Feed.php
index 73c015d..a212ac6 100644
--- a/core/modules/aggregator/lib/Drupal/aggregator/Plugin/Core/Entity/Feed.php
+++ b/core/modules/aggregator/lib/Drupal/aggregator/Plugin/Core/Entity/Feed.php
@@ -13,6 +13,8 @@
 use Drupal\Core\Entity\Annotation\EntityType;
 use Drupal\Core\Annotation\Translation;
 use Drupal\aggregator\FeedInterface;
+use Drupal\block\BlockPluginEvents;
+use Symfony\Component\EventDispatcher\GenericEvent;
 
 /**
  * Defines the aggregator feed entity class.
@@ -227,13 +229,10 @@ public static function preDelete(EntityStorageControllerInterface $storage_contr
    */
   public static function postDelete(EntityStorageControllerInterface $storage_controller, array $entities) {
     foreach ($entities as $entity) {
-      // Make sure there is no active block for this feed.
-      $block_configs = config_get_storage_names_with_prefix('plugin.core.block');
-      foreach ($block_configs as $config_id) {
-        $config = config($config_id);
-        if ($config->get('id') == 'aggregator_feed_block:' . $entity->id()) {
-          $config->delete();
-        }
+      // Inform the block plugin system that a feed has been deleted.
+      if (\Drupal::moduleHandler()->moduleExists('block')) {
+        $event = new GenericEvent('aggregator_feed_block:' . $entity->id());
+        \Drupal::service('event_dispatcher')->dispatch(BlockPluginEvents::PERMANENTLY_UNAVAILABLE, $event);
       }
     }
   }
diff --git a/core/modules/block/block.module b/core/modules/block/block.module
index 321f584..ab9976d 100644
--- a/core/modules/block/block.module
+++ b/core/modules/block/block.module
@@ -583,17 +583,6 @@ function block_user_role_delete($role) {
 }
 
 /**
- * Implements hook_menu_delete().
- */
-function block_menu_delete($menu) {
-  foreach (entity_load_multiple('block') as $block_id => $block) {
-    if ($block->get('plugin') == 'menu_menu_block:' . $menu->id()) {
-      $block->delete();
-    }
-  }
-}
-
-/**
  * Implements hook_admin_paths().
  */
 function block_admin_paths() {
diff --git a/core/modules/block/block.services.yml b/core/modules/block/block.services.yml
index 9b6b40d..e90c62a 100644
--- a/core/modules/block/block.services.yml
+++ b/core/modules/block/block.services.yml
@@ -1,7 +1,14 @@
 services:
+  block.entity.event.subscriber:
+    class: Drupal\block\BlockEntityBlockEventSubscriber
+    arguments: ['@plugin.manager.entity']
+    tags:
+      - { name: event_subscriber }
   plugin.manager.block:
     class: Drupal\block\Plugin\Type\BlockManager
     arguments: ['@container.namespaces', '@cache.block', '@language_manager', '@module_handler']
+    tags:
+      - { name: event_subscriber }
   cache.block:
     class: Drupal\Core\Cache\CacheBackendInterface
     tags:
diff --git a/core/modules/block/custom_block/lib/Drupal/custom_block/Plugin/Core/Entity/CustomBlock.php b/core/modules/block/custom_block/lib/Drupal/custom_block/Plugin/Core/Entity/CustomBlock.php
index 74dfc25..309da01 100644
--- a/core/modules/block/custom_block/lib/Drupal/custom_block/Plugin/Core/Entity/CustomBlock.php
+++ b/core/modules/block/custom_block/lib/Drupal/custom_block/Plugin/Core/Entity/CustomBlock.php
@@ -12,6 +12,8 @@
 use Drupal\Core\Entity\Annotation\EntityType;
 use Drupal\Core\Annotation\Translation;
 use Drupal\custom_block\CustomBlockInterface;
+use Drupal\block\BlockPluginEvents;
+use Symfony\Component\EventDispatcher\GenericEvent;
 
 /**
  * Defines the custom block entity class.
@@ -225,9 +227,8 @@ public function preSaveRevision(EntityStorageControllerInterface $storage_contro
    * {@inheritdoc}
    */
   public function delete() {
-    foreach ($this->getInstances() as $instance) {
-      $instance->delete();
-    }
+    $event = new GenericEvent('custom_block:' . $this->uuid->value);
+    \Drupal::service('event_dispatcher')->dispatch(BlockPluginEvents::PERMANENTLY_UNAVAILABLE, $event);
     parent::delete();
   }
 
diff --git a/core/modules/block/lib/Drupal/block/BlockEntityBlockEventSubscriber.php b/core/modules/block/lib/Drupal/block/BlockEntityBlockEventSubscriber.php
new file mode 100644
index 0000000..3070353
--- /dev/null
+++ b/core/modules/block/lib/Drupal/block/BlockEntityBlockEventSubscriber.php
@@ -0,0 +1,55 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\block\BlockEntityBlockEventSubscriber.
+ */
+
+namespace Drupal\block;
+
+use Drupal\Core\Entity\EntityManager;
+use Drupal\Core\Entity\EntityStorageControllerInterface;
+use Symfony\Component\EventDispatcher\EventSubscriberInterface;
+use Symfony\Component\EventDispatcher\GenericEvent;
+
+/**
+ * Contains block entity responses to block plugin events.
+ */
+class BlockEntityBlockEventSubscriber implements EventSubscriberInterface {
+
+  /**
+   * The block storage controller.
+   *
+   * @var \Drupal\Core\Entity\EntityStorageControllerInterface
+   */
+  private $blockStorageController;
+
+  /**
+   * Constructs a \Drupal\block\BlockEntityBlockEventSubscriber object.
+   *
+   * @param \Drupal\Core\Entity\EntityManager $entity_manager
+   *   The entity manager.
+   */
+  function __construct(EntityManager $entity_manager) {
+    $this->blockStorageController = $entity_manager->getStorageController('block');
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function getSubscribedEvents() {
+    $events[BlockPluginEvents::PERMANENTLY_UNAVAILABLE][] = 'deleteEntityByPlugin';
+    return $events;
+  }
+
+  /**
+   * Reacts on removing a block plugin.
+   */
+  public function deleteEntityByPlugin(GenericEvent $event) {
+    $plugin_id = $event->getSubject();
+    foreach ($this->blockStorageController->loadByProperties(array('plugin' => $plugin_id)) as $block) {
+      $block->delete();
+    }
+  }
+
+}
diff --git a/core/modules/block/lib/Drupal/block/BlockPluginEvents.php b/core/modules/block/lib/Drupal/block/BlockPluginEvents.php
new file mode 100644
index 0000000..c4afebe
--- /dev/null
+++ b/core/modules/block/lib/Drupal/block/BlockPluginEvents.php
@@ -0,0 +1,30 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\block\BlockPluginEvents.
+ */
+
+namespace Drupal\block;
+
+/**
+ * Contains events fired when a block plugin instance might disappear.
+ */
+class BlockPluginEvents {
+
+  /**
+   * This event is thrown when a block plugin is temporary unavailable.
+   *
+   * This could be the case, when something is disabled but not deleted.
+   */
+  const TEMPORARILY_UNAVAILABLE = 'block.unavailable.temporarily';
+
+  /**
+   * This event is thrown when a block plugin is permanently unavailable.
+   *
+   * This could be the case, when a module has been uninstalled or the data
+   * from which a block plugin was derived was deleted.
+   */
+  const PERMANENTLY_UNAVAILABLE = 'block.unavailable.permanently';
+
+}
diff --git a/core/modules/block/lib/Drupal/block/Plugin/Type/BlockManager.php b/core/modules/block/lib/Drupal/block/Plugin/Type/BlockManager.php
index 3963262..e58576a 100644
--- a/core/modules/block/lib/Drupal/block/Plugin/Type/BlockManager.php
+++ b/core/modules/block/lib/Drupal/block/Plugin/Type/BlockManager.php
@@ -6,10 +6,14 @@
 
 namespace Drupal\block\Plugin\Type;
 
+use Drupal\block\BlockPluginEvents;
 use Drupal\Core\Cache\CacheBackendInterface;
 use Drupal\Core\Extension\ModuleHandlerInterface;
 use Drupal\Core\Language\LanguageManager;
 use Drupal\Core\Plugin\DefaultPluginManager;
+use Symfony\Component\EventDispatcher\EventSubscriberInterface;
+use Symfony\Component\EventDispatcher\GenericEvent;
+
 /**
  * Manages discovery and instantiation of block plugins.
  *
@@ -17,7 +21,7 @@
  *
  * @see \Drupal\block\BlockPluginInterface
  */
-class BlockManager extends DefaultPluginManager {
+class BlockManager extends DefaultPluginManager implements EventSubscriberInterface {
 
   /**
    * Constructs a new \Drupal\block\Plugin\Type\BlockManager object.
@@ -37,4 +41,23 @@ public function __construct(\Traversable $namespaces, CacheBackendInterface $cac
     $this->alterInfo($module_handler, 'block');
     $this->setCacheBackend($cache_backend, $language_manager, 'block_plugins');
   }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function getSubscribedEvents() {
+    $events[BlockPluginEvents::PERMANENTLY_UNAVAILABLE][] = 'blockPluginRemoved';
+    return $events;
+  }
+
+  /**
+   * Reacts on removing a block plugin.
+   *
+   * @param \Symfony\Component\EventDispatcher\GenericEvent $event
+   *   The event containing the plugin ID which is updated.
+   */
+  public function blockPluginRemoved(GenericEvent $event) {
+    $this->clearCachedDefinitions();
+  }
+
 }
diff --git a/core/modules/block/lib/Drupal/block/Plugin/views/display/Block.php b/core/modules/block/lib/Drupal/block/Plugin/views/display/Block.php
index 121d2de..0adb514 100644
--- a/core/modules/block/lib/Drupal/block/Plugin/views/display/Block.php
+++ b/core/modules/block/lib/Drupal/block/Plugin/views/display/Block.php
@@ -8,9 +8,15 @@
 
 namespace Drupal\block\Plugin\views\display;
 
+use Drupal\block\BlockPluginEvents;
 use Drupal\Component\Annotation\Plugin;
 use Drupal\Core\Annotation\Translation;
 use Drupal\views\Plugin\views\display\DisplayPluginBase;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+use Symfony\Component\EventDispatcher\Event;
+use Symfony\Component\EventDispatcher\EventDispatcher;
+use Symfony\Component\EventDispatcher\EventDispatcherInterface;
+use Symfony\Component\EventDispatcher\GenericEvent;
 
 /**
  * The plugin that handles a block.
@@ -37,6 +43,13 @@ class Block extends DisplayPluginBase {
    */
   protected $usesAttachments = TRUE;
 
+  /**
+   * The event dispatcher.
+   *
+   * @var \Symfony\Component\EventDispatcher\EventDispatcherInterface
+   */
+  protected $eventDispatcher;
+
   protected function defineOptions() {
     $options = parent::defineOptions();
 
@@ -47,6 +60,35 @@ protected function defineOptions() {
   }
 
   /**
+   * Constructs a Block object.
+   *
+   * @param array $configuration
+   *   A configuration array containing information about the plugin instance.
+   * @param string $plugin_id
+   *   The plugin_id for the plugin instance.
+   * @param array $plugin_definition
+   *   The plugin implementation definition.
+   * @param \Symfony\Component\EventDispatcher\EventDispatcherInterface
+   */
+  public function __construct(array $configuration, $plugin_id, array $plugin_definition, EventDispatcherInterface $event_dispatcher) {
+    parent::__construct($configuration, $plugin_id, $plugin_definition);
+
+    $this->eventDispatcher = $event_dispatcher;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function create(ContainerInterface $container, array $configuration, $plugin_id, array $plugin_definition) {
+    return new static(
+      $configuration,
+      $plugin_id,
+      $plugin_definition,
+      $container->get('event_dispatcher')
+    );
+  }
+
+  /**
    * The display block handler returns the structure necessary for a block.
    */
   public function execute() {
@@ -185,15 +227,14 @@ public function usesExposed() {
     }
 
   /**
-   * Overrides \Drupal\views\Plugin\views\display\DisplayPluginBase::remove().
+   * {@inheritdoc}
    */
   public function remove() {
     parent::remove();
 
     $plugin_id = 'views_block:' . $this->view->storage->id() . '-' . $this->display['id'];
-    foreach (entity_load_multiple_by_properties('block', array('plugin' => $plugin_id)) as $block) {
-      $block->delete();
-    }
+    $event = new GenericEvent($plugin_id);
+    $this->eventDispatcher->dispatch(BlockPluginEvents::PERMANENTLY_UNAVAILABLE, $event);
   }
 
 }
diff --git a/core/modules/block/tests/lib/Drupal/block_test/Plugin/Type/BlockManagerTest.php b/core/modules/block/tests/lib/Drupal/block_test/Plugin/Type/BlockManagerTest.php
new file mode 100644
index 0000000..b5d5691
--- /dev/null
+++ b/core/modules/block/tests/lib/Drupal/block_test/Plugin/Type/BlockManagerTest.php
@@ -0,0 +1,51 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\block_test\Plugin\Type\BlockManagerTest.
+ */
+
+namespace Drupal\block_test\Plugin\Type;
+
+use Drupal\block\BlockPluginEvents;
+use Drupal\block\Plugin\Type\BlockManager;
+use Drupal\Tests\UnitTestCase;
+use Symfony\Component\EventDispatcher\EventDispatcher;
+use Symfony\Component\EventDispatcher\GenericEvent;
+
+/**
+ * Tests the block plugin manager.
+ *
+ * @see \Drupal\block\Plugin\Type\BlockManager
+ */
+class BlockManagerTest extends UnitTestCase {
+
+  public static function getInfo() {
+    return array(
+      'name' => 'Block Plugin Event Test',
+      'description' => 'Tests block event responses.',
+      'group' => 'Block',
+    );
+  }
+
+  /**
+   * Tests the reaction when firing block plugin events.
+   */
+  public function testBlockPluginEvents() {
+    $event_dispatcher = new EventDispatcher();
+
+    $block_manager = $this->getMockBuilder('Drupal\block\Plugin\Type\BlockManager')
+      ->disableOriginalConstructor()
+      ->setMethods(array('clearCachedDefinitions'))
+      ->getMock();
+
+    $block_manager->expects($this->once())
+      ->method('clearCachedDefinitions');
+
+    $event_dispatcher->addSubscriber($block_manager);
+    $event = new GenericEvent('test_plugin_id');
+
+    $event_dispatcher->dispatch(BlockPluginEvents::PERMANENTLY_UNAVAILABLE, $event);
+  }
+
+}
diff --git a/core/modules/menu/menu.module b/core/modules/menu/menu.module
index 850feed..2006902 100644
--- a/core/modules/menu/menu.module
+++ b/core/modules/menu/menu.module
@@ -14,10 +14,12 @@
 use Drupal\Core\Entity\EntityInterface;
 use Drupal\block\BlockPluginInterface;
 use Drupal\system\Plugin\Core\Entity\Menu;
+use Symfony\Component\EventDispatcher\GenericEvent;
 use Symfony\Component\HttpFoundation\JsonResponse;
 use Drupal\menu_link\Plugin\Core\Entity\MenuLink;
 use Drupal\menu_link\MenuLinkStorageController;
 use Drupal\node\NodeInterface;
+use Drupal\block\BlockPluginEvents;
 
 /**
  * Maximum length of menu name as entered by the user. Database length is 32
@@ -303,9 +305,11 @@ function menu_menu_predelete(Menu $menu) {
 function menu_menu_delete(Menu $menu) {
   menu_cache_clear_all();
 
-  // Invalidate the block cache to update menu-based derivatives.
-  if (module_exists('block')) {
-    Drupal::service('plugin.manager.block')->clearCachedDefinitions();
+  // Inform the block plugin system you have deleted a menu.
+  // Inform the block plugin system that a menu has been deleted.
+  if (Drupal::moduleHandler()->moduleExists('block')) {
+    $event = new GenericEvent('menu_menu_block:' . $menu->id());
+    Drupal::service('event_dispatcher')->dispatch(BlockPluginEvents::PERMANENTLY_UNAVAILABLE, $event);
   }
 }
 
