diff --git a/core/modules/outside_in/js/outside_in.es6.js b/core/modules/outside_in/js/outside_in.es6.js
index 76bb872..c73e535 100644
--- a/core/modules/outside_in/js/outside_in.es6.js
+++ b/core/modules/outside_in/js/outside_in.es6.js
@@ -9,6 +9,8 @@
   const itemsToToggleSelector = '[data-off-canvas-main-canvas], #toolbar-bar, [data-drupal-outsidein="editable"] a, [data-drupal-outsidein="editable"] button';
   const contextualItemsSelector = '[data-contextual-id] a, [data-contextual-id] button';
   const quickEditItemSelector = '[data-quickedit-entity-id]';
+  const excludedLinksSelector = '[data-outside-in-exclude] [data-outside-in-edit]';
+
 
   /**
    * Reacts to contextual links being added.
@@ -21,6 +23,10 @@
    * @listens event:drupalContextualLinkAdded
    */
   $(document).on('drupalContextualLinkAdded', (event, data) => {
+    // Remove contextual links that should be excluded.
+    // @see outside_in_block_view_alter().
+    $(excludedLinksSelector).remove();
+
     // Bind Ajax behaviors to all items showing the class.
     // @todo Fix contextual links to work with use-ajax links in
     //    https://www.drupal.org/node/2764931.
diff --git a/core/modules/outside_in/js/outside_in.js b/core/modules/outside_in/js/outside_in.js
index 95cf90e..a27c40c 100644
--- a/core/modules/outside_in/js/outside_in.js
+++ b/core/modules/outside_in/js/outside_in.js
@@ -11,8 +11,11 @@
   var itemsToToggleSelector = '[data-off-canvas-main-canvas], #toolbar-bar, [data-drupal-outsidein="editable"] a, [data-drupal-outsidein="editable"] button';
   var contextualItemsSelector = '[data-contextual-id] a, [data-contextual-id] button';
   var quickEditItemSelector = '[data-quickedit-entity-id]';
+  var excludedLinksSelector = '[data-outside-in-exclude] [data-outside-in-edit]';
 
   $(document).on('drupalContextualLinkAdded', function (event, data) {
+    $(excludedLinksSelector).remove();
+
     Drupal.attachBehaviors(data.$el[0]);
 
     data.$el.find(blockConfigureSelector).on('click.outsidein', function () {
diff --git a/core/modules/outside_in/outside_in.module b/core/modules/outside_in/outside_in.module
index 6673fa3..e645b86 100644
--- a/core/modules/outside_in/outside_in.module
+++ b/core/modules/outside_in/outside_in.module
@@ -64,6 +64,14 @@ function outside_in_block_view_alter(array &$build) {
   $build['#contextual_links']['outside_in'] = [
     'route_parameters' => [],
   ];
+  if (!\Drupal::service('outside_in.manager')->isBlockEditable($build['#plugin_id']) && isset($build['#contextual_links']['block'])) {
+    // If this block should not be editable set an attribute which will be used
+    // to remove the link on the client side.
+    // The individual links are not available here to remove.
+    // @see outside_in.js
+    $build['#attributes']['data-outside-in-exclude'] = TRUE;
+  }
+
 }
 
 /**
@@ -102,7 +110,9 @@ function outside_in_entity_type_build(array &$entity_types) {
 function outside_in_preprocess_block(&$variables) {
   // The main system block does not contain the block contextual links.
   $variables['#cache']['contexts'][] = 'outside_in_is_applied';
-  if ($variables['plugin_id'] !== 'system_main_block' && \Drupal::service('outside_in.manager')->isApplicable()) {
+  /** @var \Drupal\outside_in\OutsideInManagerInterface $outside_in_manager */
+  $outside_in_manager = \Drupal::service('outside_in.manager');
+  if (\Drupal::service('outside_in.manager')->isBlockEditable($variables['plugin_id']) && $outside_in_manager->isApplicable()) {
     // Add class and attributes to all blocks to allow Javascript to target.
     $variables['attributes']['class'][] = 'outside-in-editable';
     $variables['attributes']['data-drupal-outsidein'] = 'editable';
@@ -138,15 +148,28 @@ function outside_in_toolbar_alter(&$items) {
  * Implements hook_block_alter().
  */
 function outside_in_block_alter(&$definitions) {
-  if (!empty($definitions['system_branding_block'])) {
-    $definitions['system_branding_block']['forms']['off_canvas'] = SystemBrandingOffCanvasForm::class;
-  }
-
-  // Since menu blocks use derivatives, check the definition ID instead of
-  // relying on the plugin ID.
   foreach ($definitions as &$definition) {
-    if ($definition['id'] === 'system_menu_block') {
-      $definition['forms']['off_canvas'] = SystemMenuOffCanvasForm::class;
+    switch ($definition['id']) {
+      // Don't provide Outside-In capabilities for these two very special blocks.
+      // @see \Drupal\Core\Block\MainContentBlockPluginInterface
+      // @see \Drupal\Core\Block\TitleBlockPluginInterface
+      case 'page_title_block':
+      case 'system_main_block':
+        continue;
+
+      // Use specialized off-canvas forms when they're available.
+      // @todo move these into the corresponding block plugin annotations when Outside In becomes stable.
+      case 'system_menu_block':
+        $definition['forms']['off_canvas'] = SystemMenuOffCanvasForm::class;
+        break;
+      case 'system_branding_block':
+        $definition['forms']['off_canvas'] = SystemBrandingOffCanvasForm::class;
+        break;
+
+      // Otherwise fall back to the default off-canvas form.
+      default:
+        $definition['forms']['off_canvas'] = BlockEntityOffCanvasForm::class;
+        break;
     }
   }
 }
@@ -163,3 +186,4 @@ function outside_in_css_alter(&$css, AttachedAssetsInterface $assets) {
     $css[$path]['group'] = 200;
   }
 }
+
diff --git a/core/modules/outside_in/src/OutsideInManager.php b/core/modules/outside_in/src/OutsideInManager.php
index 666a938..26bda75 100644
--- a/core/modules/outside_in/src/OutsideInManager.php
+++ b/core/modules/outside_in/src/OutsideInManager.php
@@ -63,4 +63,12 @@ public function isApplicable() {
     return $this->account->hasPermission('administer blocks') && !$is_admin_route && !$is_admin_demo_route;
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public function isBlockEditable($plugin_id) {
+    $non_editable_blocks = ['page_title_block', 'system_main_block'];
+    return !in_array($plugin_id, $non_editable_blocks, TRUE);
+  }
+
 }
diff --git a/core/modules/outside_in/src/OutsideInManagerInterface.php b/core/modules/outside_in/src/OutsideInManagerInterface.php
index 684adb3..054074e 100644
--- a/core/modules/outside_in/src/OutsideInManagerInterface.php
+++ b/core/modules/outside_in/src/OutsideInManagerInterface.php
@@ -15,4 +15,16 @@
    */
   public function isApplicable();
 
+  /**
+   * Checks whether a block is editable by this module.
+   *
+   * @param string $plugin_id
+   *   The plugin ID for the block to check.
+   *
+   * @return bool
+   *   TRUE if the block should have the "Quick Edit" link provided by this
+   *   module.
+   */
+  public function isBlockEditable($plugin_id);
+
 }
diff --git a/core/modules/outside_in/tests/src/FunctionalJavascript/OutsideInBlockFormTest.php b/core/modules/outside_in/tests/src/FunctionalJavascript/OutsideInBlockFormTest.php
index ba865c7..087f630 100644
--- a/core/modules/outside_in/tests/src/FunctionalJavascript/OutsideInBlockFormTest.php
+++ b/core/modules/outside_in/tests/src/FunctionalJavascript/OutsideInBlockFormTest.php
@@ -498,4 +498,33 @@ protected function isLabelInputVisible() {
     return $this->getSession()->getPage()->find('css', static::LABEL_INPUT_SELECTOR)->isVisible();
   }
 
+  /**
+   * Tests that title block does not have a outside_in contextual link.
+   */
+  public function testBlockExcluded() {
+    $web_assert = $this->assertSession();
+
+    $non_excluded_block = $this->placeBlock('system_powered_by_block');
+    $excluded_block_plugin_ids = ['page_title_block', 'system_main_block'];
+    $block_selectors = [];
+    // Place blocks that should be excluded.
+    foreach ($excluded_block_plugin_ids as $excluded_block_plugin_id) {
+      // The block HTML 'id' attribute will be "block-[block_id]".
+      $block_selectors[] = $this->getBlockSelector($this->placeBlock($excluded_block_plugin_id));
+    }
+    $this->drupalGet('user');
+    // Assert that block has been marked as "editable" and contextual that
+    // should exist does.
+    $web_assert->elementExists('css', $this->getBlockSelector($non_excluded_block) . "[data-drupal-outsidein=\"editable\"]");
+    // Check each block that should be excluded.
+    foreach ($block_selectors as $block_selector) {
+      // Assert block itself exists.
+      $web_assert->elementExists('css', $block_selector);
+      // Assert that exclude block has not been marked as "editable".
+      $web_assert->elementNotExists('css', "{$block_selector}[data-drupal-outsidein=\"editable\"]");
+      // Assert that contextual that not should exist does not.
+      $web_assert->elementNotExists('css', "$block_selector [data-outside-in-edit]");
+    }
+  }
+
 }
