diff --git a/core/modules/block/block.module b/core/modules/block/block.module
index 31ef8db..a31feec 100644
--- a/core/modules/block/block.module
+++ b/core/modules/block/block.module
@@ -5,6 +5,8 @@
  * Controls the visual building blocks a page is constructed with.
  */
 
+use Drupal\Component\Plugin\Exception\PluginException;
+
 /**
  * Denotes that a block is not enabled in any region and should not be shown.
  */
@@ -361,7 +363,11 @@ function _block_rehash($theme = NULL) {
   $block_configs = config_get_storage_names_with_prefix('plugin.core.block.' . $theme);
   $regions = system_region_list($theme);
   foreach ($block_configs as $config) {
-    $blocks[$config] = block_load($config);
+    // Only list valid block instances.
+    if (!$block = block_load($config)) {
+      continue;
+    }
+    $blocks[$config] = $block;
     $config = config($config);
     $region = $config->get('region');
     $status = $config->get('status');
@@ -472,11 +478,25 @@ function block_list($region) {
  *
  * @return
  *   A block object.
+ *
+ * @todo Add block_load_multiple() and make this function a single-value wrapper.
  */
 function block_load($plugin_id, array $conf = array()) {
   $manager = drupal_container()->get('plugin.manager.block');
   if (!$block = $manager->getInstance(array('config' => $plugin_id))) {
-    $block = $manager->createInstance($plugin_id, $conf);
+    // If the block instance does not exist, try to create it.
+    try {
+      $block = $manager->createInstance($plugin_id, $conf);
+    }
+    catch (PluginException $e) {
+      $config = config($plugin_id)->get();
+      // Ignore blocks belonging to disabled modules, but re-throw valid
+      // exceptions when the module is enabled and the plugin is misconfigured.
+      if (empty($config['module']) || module_exists($config['module'])) {
+        throw $e;
+      }
+      return FALSE;
+    }
   }
   return $block;
 }
@@ -486,6 +506,8 @@ function block_load($plugin_id, array $conf = array()) {
  *
  * @return
  *   An array of blocks grouped by region.
+ *
+ * @todo Remove this function, and replace it with a block_load_multiple().
  */
 function _block_load_blocks() {
   global $theme;
@@ -493,9 +515,10 @@ function _block_load_blocks() {
   $instances = config_get_storage_names_with_prefix('plugin.core.block.' . $theme);
   $manager = drupal_container()->get('plugin.manager.block');
   foreach ($instances as $plugin_id) {
-    $block = $manager->getInstance(array('config' => $plugin_id));
-    $config = $block->getConfig();
-    $blocks[$config['region']]["$plugin_id"] = $block;
+    if ($block = block_load($plugin_id)) {
+      $config = $block->getConfig();
+      $blocks[$config['region']]["$plugin_id"] = $block;
+    }
   }
   return $blocks;
 }
diff --git a/core/modules/block/lib/Drupal/block/Tests/BlockTest.php b/core/modules/block/lib/Drupal/block/Tests/BlockTest.php
index 6a3dd0c..c607973 100644
--- a/core/modules/block/lib/Drupal/block/Tests/BlockTest.php
+++ b/core/modules/block/lib/Drupal/block/Tests/BlockTest.php
@@ -379,4 +379,101 @@ function testBlockRehash() {
     $config = $instance->getConfig();
     $this->assertEqual($config['cache'], DRUPAL_NO_CACHE, "Test block's database entry updated to DRUPAL_NO_CACHE.");
   }
+
+  /**
+   * Tests blocks belonging to disabled modules.
+   */
+  function testBlockModuleDisable() {
+    module_enable(array('block_test'));
+    $this->assertTrue(module_exists('block_test'), 'Test block module enabled.');
+
+    // Clear the block cache to load the block_test module's block definitions.
+    $manager = $this->container->get('plugin.manager.block');
+    $manager->clearCachedDefinitions();
+
+    // Add test blocks in different regions and confirm they are displayed.
+    $blocks = array();
+    $regions = array('sidebar_first', 'content', 'footer');
+    foreach ($regions as $region) {
+      $blocks[$region] = $this->drupalPlaceBlock('test_cache', array('region' => $region));
+    }
+    $this->drupalGet('');
+    foreach ($regions as $region) {
+      $this->assertText($blocks[$region]['subject']);
+    }
+
+    // Disable the block test module and refresh the definitions cache.
+    module_disable(array('block_test'), FALSE);
+    $this->assertFalse(module_exists('block_test'), 'Test block module disabled.');
+    $manager->clearCachedDefinitions();
+
+    // Ensure that the block administration page still functions as expected.
+    $this->drupalGet('admin/structure/block');
+    $this->assertResponse(200);
+    // A 200 response is possible with a fatal error, so check the title too.
+    $this->assertTitle(t('Blocks | Drupal'));
+
+    // Ensure that the disabled module's block instance is not listed.
+    foreach ($regions as $region) {
+      $this->assertNoText($blocks[$region]['subject']);
+    }
+
+    // Ensure that the disabled module's block plugin is no longer available.
+    $this->drupalGet('admin/structure/block/list/block_plugin_ui:' . variable_get('theme_default', 'stark') . '/add');
+    $this->assertNoText(t('Test block caching'));
+
+    // Confirm that the block is no longer displayed on the front page.
+    $this->drupalGet('');
+    $this->assertResponse(200);
+    foreach ($regions as $region) {
+      $this->assertNoText($blocks[$region]['subject']);
+    }
+
+    // Confirm that a different block instance can still be enabled by
+    // submitting the block library form.
+    // Emulate a POST submission rather than using drupalPlaceBlock() to ensure
+    // that the form still functions as expected.
+    $edit = array(
+      'title' => $this->randomName(8),
+      'machine_name' => $this->randomName(8),
+      'region' => 'sidebar_first',
+    );
+    $this->drupalPost('admin/structure/block/manage/system_powered_by_block/stark', $edit, t('Save block'));
+    $this->assertText(t('The block configuration has been saved.'));
+    $this->assertText($edit['title']);
+
+    // Update the weight of a block.
+    $edit = array('blocks[0][weight]' => -1);
+    $this->drupalPost('admin/structure/block', $edit, t('Save blocks'));
+    $this->assertText(t('The block settings have been updated.'));
+
+    // Re-enable the module and refresh the definitions cache.
+    module_enable(array('block_test'), FALSE);
+    $this->assertTrue(module_exists('block_test'), 'Test block module re-enabled.');
+    $manager->clearCachedDefinitions();
+
+    // Reload the admin page and confirm the block can again be configured.
+    $this->drupalGet('admin/structure/block');
+    foreach ($regions as $region) {
+      $this->assertLinkByHref(url('admin/structure/block/manage/' . $blocks[$region]['config_id'] . '/stark/config'));
+    }
+
+    // Confirm that the blocks are again displayed on the front page in the
+    // correct regions.
+    $this->drupalGet('');
+    foreach ($regions as $region) {
+      // @todo Use a proper method for this.
+      $name_pieces = explode('.', $blocks[$region]['config_id']);
+      $machine_name = array_pop($name_pieces);
+      $xpath = $this->buildXPathQuery('//div[@class=:region-class]//div[@id=:block-id]/*', array(
+        ':region-class' => 'region region-' . drupal_html_class($region),
+        ':block-id' => 'block-' . strtr(strtolower($machine_name), '-', '_'),
+    ));
+      $this->assertFieldByXPath($xpath, NULL, format_string('Block %name found in the %region region.', array(
+        '%name' => $blocks[$region]['subject'],
+        '%region' => $region,
+      )));
+    }
+  }
+
 }
