diff --git a/core/lib/Drupal/Core/Block/BlockBase.php b/core/lib/Drupal/Core/Block/BlockBase.php
index 02e5def..ebc1170 100644
--- a/core/lib/Drupal/Core/Block/BlockBase.php
+++ b/core/lib/Drupal/Core/Block/BlockBase.php
@@ -5,6 +5,7 @@
 use Drupal\block\BlockInterface;
 use Drupal\Core\Access\AccessResult;
 use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\Form\SubformImplementationHelperTrait;
 use Drupal\Core\Plugin\ContextAwarePluginAssignmentTrait;
 use Drupal\Core\Plugin\ContextAwarePluginBase;
 use Drupal\Component\Utility\Unicode;
@@ -28,6 +29,7 @@
 
   use ContextAwarePluginAssignmentTrait;
   use PluginWithFormsTrait;
+  use SubformImplementationHelperTrait;
 
   /**
    * The transliteration service.
@@ -151,6 +153,7 @@ protected function blockAccess(AccountInterface $account) {
    * @see \Drupal\Core\Block\BlockBase::blockForm()
    */
   public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
+    $this->assertSubformState($form_state);
     $definition = $this->getPluginDefinition();
     $form['provider'] = array(
       '#type' => 'value',
@@ -188,6 +191,7 @@ public function buildConfigurationForm(array $form, FormStateInterface $form_sta
    * {@inheritdoc}
    */
   public function blockForm($form, FormStateInterface $form_state) {
+    $this->assertSubformState($form_state);
     return array();
   }
 
@@ -200,6 +204,7 @@ public function blockForm($form, FormStateInterface $form_state) {
    * @see \Drupal\Core\Block\BlockBase::blockValidate()
    */
   public function validateConfigurationForm(array &$form, FormStateInterface $form_state) {
+    $this->assertSubformState($form_state);
     // Remove the admin_label form item element value so it will not persist.
     $form_state->unsetValue('admin_label');
 
@@ -209,7 +214,9 @@ public function validateConfigurationForm(array &$form, FormStateInterface $form
   /**
    * {@inheritdoc}
    */
-  public function blockValidate($form, FormStateInterface $form_state) {}
+  public function blockValidate($form, FormStateInterface $form_state) {
+    $this->assertSubformState($form_state);
+  }
 
   /**
    * {@inheritdoc}
@@ -220,6 +227,7 @@ public function blockValidate($form, FormStateInterface $form_state) {}
    * @see \Drupal\Core\Block\BlockBase::blockSubmit()
    */
   public function submitConfigurationForm(array &$form, FormStateInterface $form_state) {
+    $this->assertSubformState($form_state);
     // Process the block's submission handling if no errors occurred only.
     if (!$form_state->getErrors()) {
       $this->configuration['label'] = $form_state->getValue('label');
@@ -232,7 +240,9 @@ public function submitConfigurationForm(array &$form, FormStateInterface $form_s
   /**
    * {@inheritdoc}
    */
-  public function blockSubmit($form, FormStateInterface $form_state) {}
+  public function blockSubmit($form, FormStateInterface $form_state) {
+    $this->assertSubformState($form_state);
+  }
 
   /**
    * {@inheritdoc}
diff --git a/core/lib/Drupal/Core/Block/Plugin/Block/Broken.php b/core/lib/Drupal/Core/Block/Plugin/Block/Broken.php
index 0e4732e..de4b324 100644
--- a/core/lib/Drupal/Core/Block/Plugin/Block/Broken.php
+++ b/core/lib/Drupal/Core/Block/Plugin/Block/Broken.php
@@ -27,6 +27,7 @@ public function build() {
    * {@inheritdoc}
    */
   public function blockForm($form, FormStateInterface $form_state) {
+    parent::blockForm($form, $form_state);
     return $this->brokenMessage();
   }
 
diff --git a/core/lib/Drupal/Core/Form/SubformImplementationHelperTrait.php b/core/lib/Drupal/Core/Form/SubformImplementationHelperTrait.php
new file mode 100644
index 0000000..3ca5f97
--- /dev/null
+++ b/core/lib/Drupal/Core/Form/SubformImplementationHelperTrait.php
@@ -0,0 +1,30 @@
+<?php
+
+namespace Drupal\Core\Form;
+
+/**
+ * Helps forms implement subforms.
+ *
+ * @internal
+ */
+trait SubformImplementationHelperTrait {
+
+  /**
+   * Asserts that a form state is actually a subform state.
+   *
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
+   *   The form state to check.
+   * @param string|null $class
+   *   The name of the class whose $method method should receive a subform
+   *   state.
+   * @param string|null $method
+   *   The name of the method whose argument should receive a subform state.
+   */
+  protected function assertSubformState(FormStateInterface $form_state, $class = NULL, $method = NULL) {
+    if (!($form_state instanceof SubformStateInterface)) {
+      $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2);
+      trigger_error(sprintf('%s::%s() SHOULD receive %s on line %d, but %s was given. More information is available at https://www.drupal.org/node/2774077.', $class ? : $trace[1]['class'], $method ?: $trace[1]['function'], SubformStateInterface::class, $trace[1]['line'], get_class($form_state)), E_USER_DEPRECATED);
+    }
+  }
+
+}
diff --git a/core/lib/Drupal/Core/Menu/Plugin/Block/LocalTasksBlock.php b/core/lib/Drupal/Core/Menu/Plugin/Block/LocalTasksBlock.php
index 529fe5c..a33843b 100644
--- a/core/lib/Drupal/Core/Menu/Plugin/Block/LocalTasksBlock.php
+++ b/core/lib/Drupal/Core/Menu/Plugin/Block/LocalTasksBlock.php
@@ -120,6 +120,7 @@ public function build() {
    * {@inheritdoc}
    */
   public function blockForm($form, FormStateInterface $form_state) {
+    $form = parent::blockForm($form, $form_state);
     $config = $this->configuration;
     $defaults = $this->defaultConfiguration();
 
@@ -148,6 +149,7 @@ public function blockForm($form, FormStateInterface $form_state) {
    * {@inheritdoc}
    */
   public function blockSubmit($form, FormStateInterface $form_state) {
+    parent::blockSubmit($form, $form_state);
     $levels = $form_state->getValue('levels');
     $this->configuration['primary'] = $levels['primary'];
     $this->configuration['secondary'] = $levels['secondary'];
diff --git a/core/modules/aggregator/src/Plugin/Block/AggregatorFeedBlock.php b/core/modules/aggregator/src/Plugin/Block/AggregatorFeedBlock.php
index 7380e1d..8c051c0 100644
--- a/core/modules/aggregator/src/Plugin/Block/AggregatorFeedBlock.php
+++ b/core/modules/aggregator/src/Plugin/Block/AggregatorFeedBlock.php
@@ -107,6 +107,7 @@ protected function blockAccess(AccountInterface $account) {
    * {@inheritdoc}
    */
   public function blockForm($form, FormStateInterface $form_state) {
+    $form = parent::blockForm($form, $form_state);
     $feeds = $this->feedStorage->loadMultiple();
     $options = array();
     foreach ($feeds as $feed) {
@@ -132,6 +133,7 @@ public function blockForm($form, FormStateInterface $form_state) {
    * {@inheritdoc}
    */
   public function blockSubmit($form, FormStateInterface $form_state) {
+    parent::blockSubmit($form, $form_state);
     $this->configuration['block_count'] = $form_state->getValue('block_count');
     $this->configuration['feed'] = $form_state->getValue('feed');
   }
diff --git a/core/modules/block/tests/modules/block_test/src/Plugin/Block/TestBlockInstantiation.php b/core/modules/block/tests/modules/block_test/src/Plugin/Block/TestBlockInstantiation.php
index e5ad8da..62261d9 100644
--- a/core/modules/block/tests/modules/block_test/src/Plugin/Block/TestBlockInstantiation.php
+++ b/core/modules/block/tests/modules/block_test/src/Plugin/Block/TestBlockInstantiation.php
@@ -37,6 +37,7 @@ protected function blockAccess(AccountInterface $account) {
    * {@inheritdoc}
    */
   public function blockForm($form, FormStateInterface $form_state) {
+    $form = parent::blockForm($form, $form_state);
     $form['display_message'] = array(
       '#type' => 'textfield',
       '#title' => $this->t('Display message'),
@@ -49,6 +50,7 @@ public function blockForm($form, FormStateInterface $form_state) {
    * {@inheritdoc}
    */
   public function blockSubmit($form, FormStateInterface $form_state) {
+    parent::blockSubmit($form, $form_state);
     $this->configuration['display_message'] = $form_state->getValue('display_message');
   }
 
diff --git a/core/modules/block/tests/modules/block_test/src/Plugin/Block/TestSettingsValidationBlock.php b/core/modules/block/tests/modules/block_test/src/Plugin/Block/TestSettingsValidationBlock.php
index d1f16d7..cdf9668 100644
--- a/core/modules/block/tests/modules/block_test/src/Plugin/Block/TestSettingsValidationBlock.php
+++ b/core/modules/block/tests/modules/block_test/src/Plugin/Block/TestSettingsValidationBlock.php
@@ -19,6 +19,7 @@ class TestSettingsValidationBlock extends BlockBase {
    * {@inheritdoc}
    */
   public function blockForm($form, FormStateInterface $form_state) {
+    $form = parent::blockForm($form, $form_state);
     return ['digits' => ['#type' => 'textfield']] + $form;
   }
 
diff --git a/core/modules/block_content/src/Plugin/Block/BlockContentBlock.php b/core/modules/block_content/src/Plugin/Block/BlockContentBlock.php
index 2afd040..4c3efbd 100644
--- a/core/modules/block_content/src/Plugin/Block/BlockContentBlock.php
+++ b/core/modules/block_content/src/Plugin/Block/BlockContentBlock.php
@@ -118,6 +118,7 @@ public function defaultConfiguration() {
    * Adds body and description fields to the block configuration form.
    */
   public function blockForm($form, FormStateInterface $form_state) {
+    $form = parent::blockForm($form, $form_state);
     $uuid = $this->getDerivativeId();
     $block = $this->entityManager->loadEntityByUuid('block_content', $uuid);
     $options = $this->entityManager->getViewModeOptionsByBundle('block_content', $block->bundle());
@@ -138,6 +139,7 @@ public function blockForm($form, FormStateInterface $form_state) {
    * {@inheritdoc}
    */
   public function blockSubmit($form, FormStateInterface $form_state) {
+    parent::blockSubmit($form, $form_state);
     // Invalidate the block cache to update custom block-based derivatives.
     $this->configuration['view_mode'] = $form_state->getValue('view_mode');
     $this->blockManager->clearCachedDefinitions();
diff --git a/core/modules/book/src/Plugin/Block/BookNavigationBlock.php b/core/modules/book/src/Plugin/Block/BookNavigationBlock.php
index 6967077..3b0bc5d 100644
--- a/core/modules/book/src/Plugin/Block/BookNavigationBlock.php
+++ b/core/modules/book/src/Plugin/Block/BookNavigationBlock.php
@@ -94,6 +94,7 @@ public function defaultConfiguration() {
    * {@inheritdoc}
    */
   function blockForm($form, FormStateInterface $form_state) {
+    $form = parent::blockForm($form, $form_state);
     $options = array(
       'all pages' => $this->t('Show block on all pages'),
       'book pages' => $this->t('Show block only on book pages'),
@@ -113,6 +114,7 @@ function blockForm($form, FormStateInterface $form_state) {
    * {@inheritdoc}
    */
   public function blockSubmit($form, FormStateInterface $form_state) {
+    parent::blockSubmit($form, $form_state);
     $this->configuration['block_mode'] = $form_state->getValue('book_block_mode');
   }
 
diff --git a/core/modules/forum/src/Plugin/Block/ForumBlockBase.php b/core/modules/forum/src/Plugin/Block/ForumBlockBase.php
index e65f1df..2e22919 100644
--- a/core/modules/forum/src/Plugin/Block/ForumBlockBase.php
+++ b/core/modules/forum/src/Plugin/Block/ForumBlockBase.php
@@ -62,6 +62,7 @@ protected function blockAccess(AccountInterface $account) {
    * {@inheritdoc}
    */
   public function blockForm($form, FormStateInterface $form_state) {
+    $form = parent::blockForm($form, $form_state);
     $range = range(2, 20);
     $form['block_count'] = array(
       '#type' => 'select',
@@ -76,6 +77,7 @@ public function blockForm($form, FormStateInterface $form_state) {
    * {@inheritdoc}
    */
   public function blockSubmit($form, FormStateInterface $form_state) {
+    parent::blockSubmit($form, $form_state);
     $this->configuration['block_count'] = $form_state->getValue('block_count');
   }
 
diff --git a/core/modules/image/src/ConfigurableImageEffectBase.php b/core/modules/image/src/ConfigurableImageEffectBase.php
index 26a95bc..d19feed 100644
--- a/core/modules/image/src/ConfigurableImageEffectBase.php
+++ b/core/modules/image/src/ConfigurableImageEffectBase.php
@@ -3,6 +3,7 @@
 namespace Drupal\image;
 
 use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\Form\SubformImplementationHelperTrait;
 
 /**
  * Provides a base class for configurable image effects.
@@ -16,16 +17,27 @@
  */
 abstract class ConfigurableImageEffectBase extends ImageEffectBase implements ConfigurableImageEffectInterface {
 
+  use SubformImplementationHelperTrait;
+
+  /**
+   * {@inheritdoc}
+   */
+  public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
+    $this->assertSubformState($form_state);
+  }
+
   /**
    * {@inheritdoc}
    */
   public function validateConfigurationForm(array &$form, FormStateInterface $form_state) {
+    $this->assertSubformState($form_state);
   }
 
   /**
    * {@inheritdoc}
    */
   public function submitConfigurationForm(array &$form, FormStateInterface $form_state) {
+    $this->assertSubformState($form_state);
   }
 
 }
diff --git a/core/modules/image/src/Plugin/ImageEffect/ConvertImageEffect.php b/core/modules/image/src/Plugin/ImageEffect/ConvertImageEffect.php
index a462b67..05beca9 100644
--- a/core/modules/image/src/Plugin/ImageEffect/ConvertImageEffect.php
+++ b/core/modules/image/src/Plugin/ImageEffect/ConvertImageEffect.php
@@ -61,6 +61,7 @@ public function defaultConfiguration() {
    * {@inheritdoc}
    */
   public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
+    parent::buildConfigurationForm($form, $form_state);
     $extensions = \Drupal::service('image.toolkit.manager')->getDefaultToolkit()->getSupportedExtensions();
     $options = array_combine(
       $extensions,
diff --git a/core/modules/image/src/Plugin/ImageEffect/ResizeImageEffect.php b/core/modules/image/src/Plugin/ImageEffect/ResizeImageEffect.php
index 04a59d6..33f1cc6 100644
--- a/core/modules/image/src/Plugin/ImageEffect/ResizeImageEffect.php
+++ b/core/modules/image/src/Plugin/ImageEffect/ResizeImageEffect.php
@@ -64,6 +64,7 @@ public function defaultConfiguration() {
    * {@inheritdoc}
    */
   public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
+    parent::buildConfigurationForm($form, $form_state);
     $form['width'] = array(
       '#type' => 'number',
       '#title' => t('Width'),
diff --git a/core/modules/image/src/Plugin/ImageEffect/RotateImageEffect.php b/core/modules/image/src/Plugin/ImageEffect/RotateImageEffect.php
index df2da77..35945f3 100644
--- a/core/modules/image/src/Plugin/ImageEffect/RotateImageEffect.php
+++ b/core/modules/image/src/Plugin/ImageEffect/RotateImageEffect.php
@@ -80,6 +80,7 @@ public function defaultConfiguration() {
    * {@inheritdoc}
    */
   public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
+    parent::buildConfigurationForm($form, $form_state);
     $form['degrees'] = array(
       '#type' => 'number',
       '#default_value' => $this->configuration['degrees'],
diff --git a/core/modules/image/tests/modules/image_module_test/src/Plugin/ImageEffect/AjaxTestImageEffect.php b/core/modules/image/tests/modules/image_module_test/src/Plugin/ImageEffect/AjaxTestImageEffect.php
index a18c263..f576092 100644
--- a/core/modules/image/tests/modules/image_module_test/src/Plugin/ImageEffect/AjaxTestImageEffect.php
+++ b/core/modules/image/tests/modules/image_module_test/src/Plugin/ImageEffect/AjaxTestImageEffect.php
@@ -31,6 +31,7 @@ public function defaultConfiguration() {
    * {@inheritdoc}
    */
   public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
+    parent::buildConfigurationForm($form, $form_state);
     $form['test_parameter'] = [
       '#type' => 'number',
       '#title' => t('Test parameter'),
diff --git a/core/modules/statistics/src/Plugin/Block/StatisticsPopularBlock.php b/core/modules/statistics/src/Plugin/Block/StatisticsPopularBlock.php
index 8bd84b2..5f2aecd 100644
--- a/core/modules/statistics/src/Plugin/Block/StatisticsPopularBlock.php
+++ b/core/modules/statistics/src/Plugin/Block/StatisticsPopularBlock.php
@@ -110,6 +110,7 @@ protected function blockAccess(AccountInterface $account) {
    * {@inheritdoc}
    */
   public function blockForm($form, FormStateInterface $form_state) {
+    $form = parent::blockForm($form, $form_state);
     // Popular content block settings.
     $numbers = array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 15, 20, 25, 30, 40);
     $numbers = array('0' => $this->t('Disabled')) + array_combine($numbers, $numbers);
diff --git a/core/modules/system/src/Plugin/Block/SystemBrandingBlock.php b/core/modules/system/src/Plugin/Block/SystemBrandingBlock.php
index f6b0958..52060b5 100644
--- a/core/modules/system/src/Plugin/Block/SystemBrandingBlock.php
+++ b/core/modules/system/src/Plugin/Block/SystemBrandingBlock.php
@@ -72,6 +72,7 @@ public function defaultConfiguration() {
    * {@inheritdoc}
    */
   public function blockForm($form, FormStateInterface $form_state) {
+    $form = parent::blockForm($form, $form_state);
     // Get the theme.
     $theme = $form_state->get('block_theme');
 
@@ -140,6 +141,7 @@ public function blockForm($form, FormStateInterface $form_state) {
    * {@inheritdoc}
    */
   public function blockSubmit($form, FormStateInterface $form_state) {
+    parent::blockSubmit($form, $form_state);
     $block_branding = $form_state->getValue('block_branding');
     $this->configuration['use_site_logo'] = $block_branding['use_site_logo'];
     $this->configuration['use_site_name'] = $block_branding['use_site_name'];
diff --git a/core/modules/system/src/Plugin/Block/SystemMenuBlock.php b/core/modules/system/src/Plugin/Block/SystemMenuBlock.php
index de9ee79..9f4343a 100644
--- a/core/modules/system/src/Plugin/Block/SystemMenuBlock.php
+++ b/core/modules/system/src/Plugin/Block/SystemMenuBlock.php
@@ -73,6 +73,7 @@ public static function create(ContainerInterface $container, array $configuratio
    * {@inheritdoc}
    */
   public function blockForm($form, FormStateInterface $form_state) {
+    $form = parent::blockForm($form, $form_state);
     $config = $this->configuration;
 
     $defaults = $this->defaultConfiguration();
@@ -124,6 +125,7 @@ public static function processMenuLevelParents(&$element, FormStateInterface $fo
    * {@inheritdoc}
    */
   public function blockSubmit($form, FormStateInterface $form_state) {
+    parent::blockSubmit($form, $form_state);
     $this->configuration['level'] = $form_state->getValue('level');
     $this->configuration['depth'] = $form_state->getValue('depth');
   }
diff --git a/core/modules/views/src/Plugin/Block/ViewsBlock.php b/core/modules/views/src/Plugin/Block/ViewsBlock.php
index 43ff658..1624210 100644
--- a/core/modules/views/src/Plugin/Block/ViewsBlock.php
+++ b/core/modules/views/src/Plugin/Block/ViewsBlock.php
@@ -91,6 +91,7 @@ public function defaultConfiguration() {
    * {@inheritdoc}
    */
   public function blockForm($form, FormStateInterface $form_state) {
+    $form = parent::blockForm($form, $form_state);
     if ($this->displaySet) {
       return $this->view->display_handler->blockForm($this, $form, $form_state);
     }
@@ -102,6 +103,7 @@ public function blockForm($form, FormStateInterface $form_state) {
    * {@inheritdoc}
    */
   public function blockValidate($form, FormStateInterface $form_state) {
+    parent::blockValidate($form, $form_state);
     if ($this->displaySet) {
       $this->view->display_handler->blockValidate($this, $form, $form_state);
     }
diff --git a/core/modules/views/src/Plugin/Block/ViewsBlockBase.php b/core/modules/views/src/Plugin/Block/ViewsBlockBase.php
index 4a814d7..cbff994 100644
--- a/core/modules/views/src/Plugin/Block/ViewsBlockBase.php
+++ b/core/modules/views/src/Plugin/Block/ViewsBlockBase.php
@@ -167,6 +167,7 @@ public function buildConfigurationForm(array $form, FormStateInterface $form_sta
    * {@inheritdoc}
    */
   public function blockSubmit($form, FormStateInterface $form_state) {
+    parent::blockSubmit($form, $form_state);
     if (!$form_state->isValueEmpty('views_label_checkbox')) {
       $this->configuration['views_label'] = $form_state->getValue('views_label');
     }
