diff --git a/core/lib/Drupal/Core/Plugin/DefaultPluginManager.php b/core/lib/Drupal/Core/Plugin/DefaultPluginManager.php
index e1d0731..66a4284 100644
--- a/core/lib/Drupal/Core/Plugin/DefaultPluginManager.php
+++ b/core/lib/Drupal/Core/Plugin/DefaultPluginManager.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\Core\Plugin;
 
+use Drupal\block\BlockPluginEvents;
 use Drupal\Component\Plugin\Discovery\CachedDiscoveryInterface;
 use Drupal\Component\Plugin\Discovery\DiscoveryCachedTrait;
 use Drupal\Component\Plugin\Exception\PluginNotFoundException;
@@ -20,13 +21,14 @@
 use Drupal\Core\Language\LanguageManagerInterface;
 use Drupal\Core\Plugin\Discovery\AnnotatedClassDiscovery;
 use Drupal\Core\Plugin\Factory\ContainerFactory;
+use Symfony\Component\EventDispatcher\GenericEvent;
 
 /**
  * Base class for plugin managers.
  *
  * @ingroup plugin_api
  */
-class DefaultPluginManager extends PluginManagerBase implements PluginManagerInterface, CachedDiscoveryInterface {
+class DefaultPluginManager extends PluginManagerBase implements PluginManagerInterface, CachedDiscoveryInterface, DefaultPluginManagerInterface {
 
   use DiscoveryCachedTrait;
 
@@ -105,24 +107,7 @@ public function __construct($subdir, \Traversable $namespaces, ModuleHandlerInte
   }
 
   /**
-   * 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()) {
     $this->cacheBackend = $cache_backend;
@@ -241,4 +226,17 @@ protected function findDefinitions() {
     return $definitions;
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public function removePluginId($plugin_id, $permanent = TRUE, array $conditions = array()) {
+    /** @var \Symfony\Component\EventDispatcher\EventDispatcherInterface $event_dispatcher */
+    $event_dispatcher = \Drupal::service('event_dispatcher');
+    $event_dispatcher->dispatch($permanent ? BlockPluginEvents::PERMANENTLY_UNAVAILABLE : BlockPluginEvents::TEMPORARILY_UNAVAILABLE, new GenericEvent(array(
+      'plugin_id' => $plugin_id,
+      'permanent' => $permanent,
+      'conditions' => $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..9f21d72
--- /dev/null
+++ b/core/lib/Drupal/Core/Plugin/DefaultPluginManagerInterface.php
@@ -0,0 +1,58 @@
+<?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 a plugin with a specified ID disappears.
+   *
+   * The plugin might disappear permanent, when something else is deleted or
+   * will be back later, when just something is disabled.
+   *
+   * @param string $plugin_id
+   *   The plugin to remove.
+   * @param bool $permanent
+   *   (optional) Indicates whether the plugin is removed or just temporarily
+   *   removed.
+   * @param array $conditions
+   *   (optional) An array of information used by the subscribers to know how
+   *   to react.
+   */
+  public function removePluginId($plugin_id, $permanent = TRUE, array $conditions = array());
+
+}
+
diff --git a/core/modules/aggregator/src/Entity/Feed.php b/core/modules/aggregator/src/Entity/Feed.php
index 7aff3d0..f31432b 100644
--- a/core/modules/aggregator/src/Entity/Feed.php
+++ b/core/modules/aggregator/src/Entity/Feed.php
@@ -110,15 +110,10 @@ 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));
+    /** @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->removePluginId('aggregator_feed_block', FALSE, array('conditions' => array('settings.feed' => $entity->id())));
       }
     }
   }
diff --git a/core/modules/aggregator/src/Tests/AggregatorRenderingTest.php b/core/modules/aggregator/src/Tests/AggregatorRenderingTest.php
index d967d1b..be436cc 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.
+    $feed->block = 5;
+    $feed->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 e5e58d1..a7f7330 100644
--- a/core/modules/block/block.services.yml
+++ b/core/modules/block/block.services.yml
@@ -2,6 +2,8 @@ services:
   plugin.manager.block:
     class: Drupal\block\BlockManager
     arguments: ['@container.namespaces', '@cache.discovery', '@module_handler', '@string_translation']
+    tags:
+      - { name: event_subscriber }
   theme.negotiator.block.admin_demo:
     class: Drupal\block\Theme\AdminDemoNegotiator
     tags:
@@ -21,3 +23,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..e569a8a
--- /dev/null
+++ b/core/modules/block/src/BlockEntityBlockEventSubscriber.php
@@ -0,0 +1,73 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\block\BlockEntityBlockEventSubscriber.
+ */
+
+namespace Drupal\block;
+
+use Drupal\Core\Entity\EntityManagerInterface;
+use Drupal\Core\Entity\Query\QueryFactory;
+use Symfony\Component\EventDispatcher\EventSubscriberInterface;
+use Symfony\Component\EventDispatcher\GenericEvent;
+
+/**
+ * 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[BlockPluginEvents::PERMANENTLY_UNAVAILABLE][] = 'deleteEntityByPlugin';
+    return $events;
+  }
+
+  /**
+   * Reacts on removing a block plugin.
+   */
+  public function deleteEntityByPlugin(GenericEvent $event) {
+    $plugin_id = $event->getSubject();
+    $query = $this->queryFactory->get('block');
+    $query->condition('plugin', $plugin_id);
+    if ($event->hasArgument('conditions') && $conditions = $event->getArgument('conditions')) {
+      foreach ($conditions 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/src/BlockManager.php b/core/modules/block/src/BlockManager.php
index 706af51..a6b9c95 100644
--- a/core/modules/block/src/BlockManager.php
+++ b/core/modules/block/src/BlockManager.php
@@ -13,6 +13,8 @@
 use Drupal\Core\Plugin\DefaultPluginManager;
 use Drupal\Core\StringTranslation\TranslationInterface;
 use Drupal\Core\StringTranslation\StringTranslationTrait;
+use Symfony\Component\EventDispatcher\EventSubscriberInterface;
+use Symfony\Component\EventDispatcher\GenericEvent;
 
 /**
  * Manages discovery and instantiation of block plugins.
@@ -21,7 +23,7 @@
  *
  * @see \Drupal\block\BlockPluginInterface
  */
-class BlockManager extends DefaultPluginManager implements BlockManagerInterface {
+class BlockManager extends DefaultPluginManager implements BlockManagerInterface, EventSubscriberInterface {
 
   use StringTranslationTrait;
   use ContextAwarePluginManagerTrait;
@@ -115,4 +117,22 @@ public function getSortedDefinitions() {
     return $definitions;
   }
 
+  /**
+   * {@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/src/BlockManagerInterface.php b/core/modules/block/src/BlockManagerInterface.php
index 6656004..b6598f8 100644
--- a/core/modules/block/src/BlockManagerInterface.php
+++ b/core/modules/block/src/BlockManagerInterface.php
@@ -8,11 +8,12 @@
 namespace Drupal\block;
 
 use Drupal\Core\Plugin\Context\ContextAwarePluginManagerInterface;
+use Drupal\Core\Plugin\DefaultPluginManagerInterface;
 
 /**
  * Provides an interface for the discovery and instantiation of block plugins.
  */
-interface BlockManagerInterface extends ContextAwarePluginManagerInterface {
+interface BlockManagerInterface extends ContextAwarePluginManagerInterface, DefaultPluginManagerInterface {
 
   /**
    * Gets the names of all block categories.
diff --git a/core/modules/block/src/BlockPluginEvents.php b/core/modules/block/src/BlockPluginEvents.php
new file mode 100644
index 0000000..29dce73
--- /dev/null
+++ b/core/modules/block/src/BlockPluginEvents.php
@@ -0,0 +1,30 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\block\BlockPluginEvents.
+ */
+
+namespace Drupal\block;
+
+/**
+ * Contains events fired when a block plugin instance becomes unavailable.
+ */
+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/src/Plugin/views/display/Block.php b/core/modules/block/src/Plugin/views/display/Block.php
index 0e2e968..50bd232 100644
--- a/core/modules/block/src/Plugin/views/display/Block.php
+++ b/core/modules/block/src/Plugin/views/display/Block.php
@@ -8,11 +8,13 @@
 
 namespace Drupal\block\Plugin\views\display;
 
+use Drupal\block\BlockManagerInterface;
 use Drupal\Component\Utility\String;
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\views\Plugin\Block\ViewsBlock;
 use Drupal\views\Plugin\views\display\DisplayPluginBase;
 use Drupal\views\Views;
+use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
  * The plugin that handles a block.
@@ -42,6 +44,15 @@ class Block extends DisplayPluginBase {
    */
   protected $usesAttachments = TRUE;
 
+  /**
+   * The block manager.
+   *
+   *
+   * @var \Drupal\block\BlockManagerInterface
+   */
+  protected $blockManager;
+
+
   protected function defineOptions() {
     $options = parent::defineOptions();
 
@@ -59,6 +70,33 @@ protected function defineOptions() {
   }
 
   /**
+   * Constructs a new 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 mixed $plugin_definition
+   *   The plugin implementation definition.
+   * @param \Drupal\block\BlockManagerInterface $block_manager
+   *   The block plugin manager.
+   */
+  public function __construct(array $configuration, $plugin_id, $plugin_definition, BlockManagerInterface $block_manager) {
+    parent::__construct($configuration, $plugin_id, $plugin_definition);
+
+    $this->blockManager = $block_manager;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
+    return new static($configuration, $plugin_id, $plugin_definition,
+      $container->get('plugin.manager.block')
+    );
+  }
+
+  /**
    * Returns plugin-specific settings for the block.
    *
    * @param array $settings
@@ -318,15 +356,13 @@ 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();
-    }
+    $this->blockManager->removePluginId($plugin_id, TRUE);
   }
 
 }
diff --git a/core/modules/block/tests/src/BlockManagerTest.php b/core/modules/block/tests/src/BlockManagerTest.php
new file mode 100644
index 0000000..ca6334f
--- /dev/null
+++ b/core/modules/block/tests/src/BlockManagerTest.php
@@ -0,0 +1,48 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\block\Tests\BlockManagerTest.
+ */
+
+namespace Drupal\block\Tests;
+
+use Drupal\block\BlockPluginEvents;
+use Drupal\Tests\UnitTestCase;
+use Symfony\Component\EventDispatcher\EventDispatcher;
+use Symfony\Component\EventDispatcher\GenericEvent;
+
+
+/**
+ * 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\block\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/block_content/src/Entity/BlockContent.php b/core/modules/block_content/src/Entity/BlockContent.php
index 630fe51..a5784fa 100644
--- a/core/modules/block_content/src/Entity/BlockContent.php
+++ b/core/modules/block_content/src/Entity/BlockContent.php
@@ -127,10 +127,11 @@ public function preSaveRevision(EntityStorageInterface $storage, \stdClass $reco
    * {@inheritdoc}
    */
   public function delete() {
-    foreach ($this->getInstances() as $instance) {
-      $instance->delete();
-    }
     parent::delete();
+
+    /** @var \Drupal\block\BlockManagerInterface $block_manager */
+    $block_manager = \Drupal::service('plugin.manager.block');
+    $block_manager->removePluginId('custom_block:' . $this->uuid());
   }
 
   /**
diff --git a/core/modules/system/src/Entity/Menu.php b/core/modules/system/src/Entity/Menu.php
index 756728f..e5d0f9f 100644
--- a/core/modules/system/src/Entity/Menu.php
+++ b/core/modules/system/src/Entity/Menu.php
@@ -64,4 +64,15 @@ public function isLocked() {
     return (bool) $this->locked;
   }
 
+  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->removePluginId('menu_menu_block:' . $entity->id());
+    }
+  }
+
+
 }
