diff --git a/core/lib/Drupal/Component/Utility/FinalDeprecationTrait.php b/core/lib/Drupal/Component/Utility/FinalDeprecationTrait.php
new file mode 100644
index 0000000000..8b35ae2b95
--- /dev/null
+++ b/core/lib/Drupal/Component/Utility/FinalDeprecationTrait.php
@@ -0,0 +1,27 @@
+<?php
+
+namespace Drupal\Component\Utility;
+
+/**
+ * Trait to mark a class to be declared final in Drupal 9.0.0.
+ *
+ * @package Drupal\Component\Utility
+ */
+trait FinalDeprecationTrait {
+
+  /**
+   * Triggers a deprecation error if a class is extended.
+   *
+   * @param string|null $error
+   *   The error message to trigger (optional).
+   */
+  protected function preventExtension($error = NULL) {
+    if (self::class !== static::class) {
+      if (!$error) {
+        $error = "It is deprecated to extend " . self::class . " as of 8.7.0, and this class will be marked final as of Drupal 9.0.0.  Extend the base class, or instantiate a copy of this object in yours to use its public methods.";
+      }
+      @trigger_error($error, E_USER_DEPRECATED);
+    }
+  }
+
+}
diff --git a/core/modules/action/src/Plugin/Action/EmailAction.php b/core/modules/action/src/Plugin/Action/EmailAction.php
index 0791a3f998..b4487b7aa5 100644
--- a/core/modules/action/src/Plugin/Action/EmailAction.php
+++ b/core/modules/action/src/Plugin/Action/EmailAction.php
@@ -4,6 +4,7 @@
 
 use Drupal\Component\Render\PlainTextOutput;
 use Drupal\Component\Utility\EmailValidatorInterface;
+use Drupal\Component\Utility\FinalDeprecationTrait;
 use Drupal\Core\Access\AccessResult;
 use Drupal\Core\Action\ConfigurableActionBase;
 use Drupal\Core\Entity\EntityManagerInterface;
@@ -27,6 +28,8 @@
  */
 class EmailAction extends ConfigurableActionBase implements ContainerFactoryPluginInterface {
 
+  use FinalDeprecationTrait;
+
   /**
    * The token service.
    *
@@ -92,6 +95,7 @@ class EmailAction extends ConfigurableActionBase implements ContainerFactoryPlug
    *   The email validator.
    */
   public function __construct(array $configuration, $plugin_id, $plugin_definition, Token $token, EntityManagerInterface $entity_manager, LoggerInterface $logger, MailManagerInterface $mail_manager, LanguageManagerInterface $language_manager, EmailValidatorInterface $email_validator) {
+    $this->preventExtension();
     parent::__construct($configuration, $plugin_id, $plugin_definition);
 
     $this->token = $token;
diff --git a/core/modules/migrate/src/Event/MigrateImportEvent.php b/core/modules/migrate/src/Event/MigrateImportEvent.php
index 954117156d..9318c5d7b8 100644
--- a/core/modules/migrate/src/Event/MigrateImportEvent.php
+++ b/core/modules/migrate/src/Event/MigrateImportEvent.php
@@ -2,7 +2,22 @@
 
 namespace Drupal\migrate\Event;
 
+use Drupal\Component\Utility\FinalDeprecationTrait;
+use Drupal\migrate\MigrateMessageInterface;
+use Drupal\migrate\Plugin\MigrationInterface;
+
 /**
  * Wraps a pre- or post-import event for event listeners.
  */
-class MigrateImportEvent extends EventBase {}
+class MigrateImportEvent extends EventBase {
+  use FinalDeprecationTrait;
+
+  /**
+   * {@inheritdoc}
+   */
+  public function __construct(MigrationInterface $migration, MigrateMessageInterface $message) {
+    $this->preventExtension();
+    parent::__construct($migration, $message);
+  }
+
+}
diff --git a/core/modules/path/src/Controller/PathController.php b/core/modules/path/src/Controller/PathController.php
index 26fe851710..74963ff4b2 100644
--- a/core/modules/path/src/Controller/PathController.php
+++ b/core/modules/path/src/Controller/PathController.php
@@ -2,6 +2,7 @@
 
 namespace Drupal\path\Controller;
 
+use Drupal\Component\Utility\FinalDeprecationTrait;
 use Drupal\Component\Utility\Unicode;
 use Drupal\Core\Controller\ControllerBase;
 use Drupal\Core\Path\AliasStorageInterface;
@@ -15,6 +16,8 @@
  */
 class PathController extends ControllerBase {
 
+  use FinalDeprecationTrait;
+
   /**
    * The path alias storage.
    *
@@ -38,6 +41,7 @@ class PathController extends ControllerBase {
    *   The path alias manager.
    */
   public function __construct(AliasStorageInterface $alias_storage, AliasManagerInterface $alias_manager) {
+    $this->preventExtension();
     $this->aliasStorage = $alias_storage;
     $this->aliasManager = $alias_manager;
   }
diff --git a/core/modules/path/src/Form/PathFilterForm.php b/core/modules/path/src/Form/PathFilterForm.php
index 52b0ffbb94..59e74bff56 100644
--- a/core/modules/path/src/Form/PathFilterForm.php
+++ b/core/modules/path/src/Form/PathFilterForm.php
@@ -2,6 +2,7 @@
 
 namespace Drupal\path\Form;
 
+use Drupal\Component\Utility\FinalDeprecationTrait;
 use Drupal\Core\Form\FormBase;
 use Drupal\Core\Form\FormStateInterface;
 
@@ -12,6 +13,15 @@
  */
 class PathFilterForm extends FormBase {
 
+  use FinalDeprecationTrait;
+
+  /**
+   * Constructs a PathFilterForm object.
+   */
+  public function __construct() {
+    $this->preventExtension();
+  }
+
   /**
    * {@inheritdoc}
    */
diff --git a/core/modules/views_ui/src/ParamConverter/ViewUIConverter.php b/core/modules/views_ui/src/ParamConverter/ViewUIConverter.php
index bb884a237d..7636945a60 100644
--- a/core/modules/views_ui/src/ParamConverter/ViewUIConverter.php
+++ b/core/modules/views_ui/src/ParamConverter/ViewUIConverter.php
@@ -2,6 +2,7 @@
 
 namespace Drupal\views_ui\ParamConverter;
 
+use Drupal\Component\Utility\FinalDeprecationTrait;
 use Drupal\Core\Config\ConfigFactoryInterface;
 use Drupal\Core\Entity\EntityRepositoryInterface;
 use Drupal\Core\Entity\EntityTypeManagerInterface;
@@ -31,6 +32,7 @@
  */
 class ViewUIConverter extends AdminPathConfigEntityConverter implements ParamConverterInterface {
 
+  use FinalDeprecationTrait;
   /**
    * Stores the tempstore factory.
    *
@@ -55,6 +57,7 @@ class ViewUIConverter extends AdminPathConfigEntityConverter implements ParamCon
    *   The entity repository.
    */
   public function __construct(EntityTypeManagerInterface $entity_type_manager, SharedTempStoreFactory $temp_store_factory, ConfigFactoryInterface $config_factory = NULL, AdminContext $admin_context = NULL, LanguageManagerInterface $language_manager = NULL, EntityRepositoryInterface $entity_repository = NULL) {
+    $this->preventExtension();
     // The config factory and admin context are new arguments due to changing
     // the parent. Avoid an error on updated sites by falling back to getting
     // them from the container.
diff --git a/core/tests/Drupal/Tests/Component/Utility/FinalDeprecationTraitTest.php b/core/tests/Drupal/Tests/Component/Utility/FinalDeprecationTraitTest.php
new file mode 100644
index 0000000000..5c7577a02c
--- /dev/null
+++ b/core/tests/Drupal/Tests/Component/Utility/FinalDeprecationTraitTest.php
@@ -0,0 +1,74 @@
+<?php
+
+namespace Drupal\Tests\Component\Utility;
+
+use Drupal\Component\Utility\FinalDeprecationTrait;
+use PHPUnit\Framework\TestCase;
+
+/**
+ * Tests deprecation errors from FinalDeprecationTrait.
+ *
+ * @group Utility
+ * @group legacy
+ */
+class FinalDeprecationTraitTest extends TestCase {
+
+  /**
+   * Tests the generic error message.
+   *
+   * @expectedDeprecation It is deprecated to extend Drupal\Tests\Component\Utility\Foo as of 8.7.0, and this class will be marked final as of Drupal 9.0.0.  Extend the base class, or instantiate a copy of this object in yours to use its public methods.
+   */
+  public function testDeprecation() {
+    new Bar();
+  }
+
+  /**
+   * Tests a custom error message.
+   *
+   * @expectedDeprecation Please good sir, I beg you not to extend Baz. Just let Baz be Baz. Baz is perfect just the way Baz is.
+   */
+  public function testDeprecationWithMessage() {
+    new Qux();
+  }
+
+}
+
+/**
+ * A class to be made final.
+ */
+class Foo {
+  use FinalDeprecationTrait;
+
+  /**
+   * Constructs a Foo object.
+   */
+  public function __construct() {
+    $this->preventExtension();
+  }
+
+}
+
+/**
+ * An extension class.
+ */
+class Bar extends Foo {}
+
+/**
+ * A class to be made final with a custom error message.
+ */
+class Baz {
+  use FinalDeprecationTrait;
+
+  /**
+   * Constructs a Baz object.
+   */
+  public function __construct() {
+    $this->preventExtension("Please good sir, I beg you not to extend Baz. Just let Baz be Baz. Baz is perfect just the way Baz is.");
+  }
+
+}
+
+/**
+ * An extension class.
+ */
+class Qux extends Baz {}
