diff --git a/core/lib/Drupal/Core/Entity/EntityDecorator.php b/core/lib/Drupal/Core/Entity/EntityDecorator.php
new file mode 100644
index 0000000000..41293c2ebb
--- /dev/null
+++ b/core/lib/Drupal/Core/Entity/EntityDecorator.php
@@ -0,0 +1,403 @@
+<?php
+
+namespace Drupal\Core\Entity;
+
+use Drupal\Core\Session\AccountInterface;
+
+/**
+ * Provides a base class for entity decorators to extend.
+ */
+abstract class EntityDecorator implements EntityInterface {
+
+  /**
+   * The decorated entity.
+   *
+   * @var \Drupal\Core\Entity\EntityInterface
+   */
+  protected $subject;
+
+  /**
+   * EntityDecorator constructor.
+   *
+   * @param \Drupal\Core\Entity\EntityInterface $subject
+   *   The entity being decorated.
+   */
+  public function __construct(EntityInterface $subject) {
+    $this->subject = $subject instanceof static ? $subject->getEntity() : $subject;
+  }
+
+  /**
+   * Passes through all unknown calls onto the subject.
+   */
+  public function __call($method, $args) {
+    return call_user_func_array([$this->subject, $method], $args);
+  }
+
+  /**
+   * Implements the magic method for getting object properties.
+   */
+  public function &__get($name) {
+    $value = &$this->subject->{$name};
+    return $value;
+  }
+
+  /**
+   * Implements the magic method for setting object properties.
+   */
+  public function __set($name, $value) {
+    $this->subject->{$name} = $value;
+  }
+
+  /**
+   * Implements the magic method for isset().
+   */
+  public function __isset($name) {
+    return isset($this->subject->{$name});
+  }
+
+  /**
+   * Implements the magic method for unset().
+   */
+  public function __unset($name) {
+    unset($this->subject->{$name});
+  }
+
+  /**
+   * Gets the decorated entity.
+   *
+   * @return \Drupal\Core\Entity\EntityInterface
+   *   The decorated entity.
+   */
+  public function getEntity() {
+    return $this->subject;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function access($operation, AccountInterface $account = NULL, $return_as_object = FALSE) {
+    return $this->subject->access($operation, $account, $return_as_object);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getCacheContexts() {
+    return $this->subject->getCacheContexts();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getCacheTags() {
+    return $this->subject->getCacheTags();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getCacheMaxAge() {
+    return $this->subject->getCacheMaxAge();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function uuid() {
+    return $this->subject->uuid();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function id() {
+    return $this->subject->id();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function language() {
+    return $this->subject->language();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function isNew() {
+    return $this->subject->isNew();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function enforceIsNew($value = TRUE) {
+    $this->subject->enforceIsNew($value);
+    return $this;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getEntityTypeId() {
+    return $this->subject->getEntityTypeId();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function bundle() {
+    return $this->subject->bundle();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function label() {
+    return $this->subject->label();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function urlInfo($rel = 'canonical', array $options = []) {
+    return $this->subject->urlInfo($rel, $options);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function toUrl($rel = 'canonical', array $options = []) {
+    return $this->subject->toUrl($rel, $options);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function url($rel = 'canonical', $options = []) {
+    return $this->subject->url($rel, $options);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function link($text = NULL, $rel = 'canonical', array $options = []) {
+    return $this->subject->link($text, $rel, $options);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function toLink($text = NULL, $rel = 'canonical', array $options = []) {
+    return $this->subject->toLink($text, $rel, $options);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function hasLinkTemplate($key) {
+    return $this->subject->hasLinkTemplate($key);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function uriRelationships() {
+    return $this->subject->uriRelationships();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function load($id) {
+    throw new \LogicException('Static methods cannot be called on the decorated entity');
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function loadMultiple(array $ids = NULL) {
+    throw new \LogicException('Static methods cannot be called on the decorated entity');
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function create(array $values = []) {
+    throw new \LogicException('Static methods cannot be called on the decorated entity');
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function save() {
+    return $this->subject->save();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function delete() {
+    return $this->subject->delete();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function preSave(EntityStorageInterface $storage) {
+    $this->subject->preSave($storage);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function postSave(EntityStorageInterface $storage, $update = TRUE) {
+    return $this->subject->postSave($storage, $update);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function preCreate(EntityStorageInterface $storage, array &$values) {
+    throw new \LogicException('Static methods cannot be called on the decorated entity');
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function postCreate(EntityStorageInterface $storage) {
+    return $this->subject->postCreate($storage);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function preDelete(EntityStorageInterface $storage, array $entities) {
+    throw new \LogicException('Static methods cannot be called on the decorated entity');
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function postDelete(EntityStorageInterface $storage, array $entities) {
+    throw new \LogicException('Static methods cannot be called on the decorated entity');
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function postLoad(EntityStorageInterface $storage, array &$entities) {
+    throw new \LogicException('Static methods cannot be called on the decorated entity');
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function createDuplicate() {
+    return $this->subject->createDuplicate();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getEntityType() {
+    return $this->subject->getEntityType();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function referencedEntities() {
+    return $this->subject->referencedEntities();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getOriginalId() {
+    return $this->subject->getOriginalId();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getCacheTagsToInvalidate() {
+    return $this->subject->getCacheTagsToInvalidate();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function setOriginalId($id) {
+    $this->subject->setOriginalId($id);
+    return $this;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getTypedData() {
+    return $this->subject->getTypedData();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getConfigDependencyKey() {
+    return $this->subject->getConfigDependencyKey();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getConfigDependencyName() {
+    return $this->subject->getConfigDependencyName();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getConfigTarget() {
+    return $this->subject->getConfigTarget();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function toArray() {
+    return $this->subject->toArray();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function addCacheContexts(array $cache_contexts) {
+    $this->subject->addCacheContexts($cache_contexts);
+    return $this;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function addCacheTags(array $cache_tags) {
+    $this->subject->addCacheTags($cache_tags);
+    return $this;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function mergeCacheMaxAge($max_age) {
+    $this->subject->mergeCacheMaxAge($max_age);
+    return $this;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function addCacheableDependency($other_object) {
+    $this->subject->addCacheableDependency($other_object);
+    return $this;
+  }
+
+}
diff --git a/core/modules/views_ui/src/ViewUI.php b/core/modules/views_ui/src/ViewUI.php
index 2e7fabd62b..7ffee6f0c0 100644
--- a/core/modules/views_ui/src/ViewUI.php
+++ b/core/modules/views_ui/src/ViewUI.php
@@ -6,6 +6,7 @@
 use Drupal\Component\Utility\Timer;
 use Drupal\Core\EventSubscriber\AjaxResponseSubscriber;
 use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\Entity\EntityDecorator;
 use Drupal\views\Views;
 use Drupal\Core\Entity\EntityStorageInterface;
 use Drupal\views\ViewExecutable;
@@ -21,7 +22,7 @@
 /**
  * Stores UI related temporary settings.
  */
-class ViewUI implements ViewEntityInterface {
+class ViewUI extends EntityDecorator implements ViewEntityInterface {
 
   /**
    * Indicates if a view is currently being edited.
@@ -90,7 +91,7 @@ class ViewUI implements ViewEntityInterface {
    *
    * @var \Drupal\views\ViewEntityInterface
    */
-  protected $storage;
+  protected $subject;
 
   /**
    * Stores a list of database queries run beside the main one from views.
@@ -142,15 +143,15 @@ class ViewUI implements ViewEntityInterface {
    */
   public function __construct(ViewEntityInterface $storage) {
     $this->entityType = 'view';
-    $this->storage = $storage;
+    $this->subject = $storage;
   }
 
   /**
    * {@inheritdoc}
    */
   public function get($property_name, $langcode = NULL) {
-    if (property_exists($this->storage, $property_name)) {
-      return $this->storage->get($property_name, $langcode);
+    if (property_exists($this->subject, $property_name)) {
+      return $this->subject->get($property_name, $langcode);
     }
 
     return isset($this->{$property_name}) ? $this->{$property_name} : NULL;
@@ -160,15 +161,15 @@ public function get($property_name, $langcode = NULL) {
    * {@inheritdoc}
    */
   public function setStatus($status) {
-    return $this->storage->setStatus($status);
+    return $this->subject->setStatus($status);
   }
 
   /**
    * {@inheritdoc}
    */
   public function set($property_name, $value, $notify = TRUE) {
-    if (property_exists($this->storage, $property_name)) {
-      $this->storage->set($property_name, $value);
+    if (property_exists($this->subject, $property_name)) {
+      $this->subject->set($property_name, $value);
     }
     else {
       $this->{$property_name} = $value;
@@ -571,7 +572,7 @@ public function renderPreview($display_id, $args = []) {
       $request = Request::createFromGlobals();
       $request->attributes->set(RouteObjectInterface::ROUTE_NAME, 'entity.view.preview_form');
       $request->attributes->set(RouteObjectInterface::ROUTE_OBJECT, \Drupal::service('router.route_provider')->getRouteByName('entity.view.preview_form'));
-      $request->attributes->set('view', $this->storage);
+      $request->attributes->set('view', $this->subject);
       $request->attributes->set('display_id', $display_id);
       $raw_parameters = new ParameterBag();
       $raw_parameters->set('view', $this->id());
@@ -891,67 +892,11 @@ public function isLocked() {
     return is_object($this->lock) && ($this->lock->owner != \Drupal::currentUser()->id());
   }
 
-  /**
-   * Passes through all unknown calls onto the storage object.
-   */
-  public function __call($method, $args) {
-    return call_user_func_array([$this->storage, $method], $args);
-  }
-
   /**
    * {@inheritdoc}
    */
   public function &getDisplay($display_id) {
-    return $this->storage->getDisplay($display_id);
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function id() {
-    return $this->storage->id();
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function uuid() {
-    return $this->storage->uuid();
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function isNew() {
-    return $this->storage->isNew();
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getEntityTypeId() {
-    return $this->storage->getEntityTypeId();
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function bundle() {
-    return $this->storage->bundle();
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getEntityType() {
-    return $this->storage->getEntityType();
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function createDuplicate() {
-    return $this->storage->createDuplicate();
+    return $this->subject->getDisplay($display_id);
   }
 
   /**
@@ -975,380 +920,166 @@ public static function create(array $values = []) {
     return View::create($values);
   }
 
-  /**
-   * {@inheritdoc}
-   */
-  public function delete() {
-    return $this->storage->delete();
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function save() {
-    return $this->storage->save();
-  }
-
   /**
    * {@inheritdoc}
    */
   public function urlInfo($rel = 'edit-form', array $options = []) {
-    return $this->storage->urlInfo($rel, $options);
+    return $this->subject->urlInfo($rel, $options);
   }
 
   /**
    * {@inheritdoc}
    */
   public function toUrl($rel = 'edit-form', array $options = []) {
-    return $this->storage->toUrl($rel, $options);
+    return $this->subject->toUrl($rel, $options);
   }
 
   /**
    * {@inheritdoc}
    */
   public function link($text = NULL, $rel = 'edit-form', array $options = []) {
-    return $this->storage->link($text, $rel, $options);
+    return $this->subject->link($text, $rel, $options);
   }
 
   /**
    * {@inheritdoc}
    */
   public function toLink($text = NULL, $rel = 'edit-form', array $options = []) {
-    return $this->storage->toLink($text, $rel, $options);
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function label() {
-    return $this->storage->label();
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function enforceIsNew($value = TRUE) {
-    return $this->storage->enforceIsNew($value);
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function toArray() {
-    return $this->storage->toArray();
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function language() {
-    return $this->storage->language();
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function access($operation = 'view', AccountInterface $account = NULL, $return_as_object = FALSE) {
-    return $this->storage->access($operation, $account, $return_as_object);
+    return $this->subject->toLink($text, $rel, $options);
   }
 
   /**
    * {@inheritdoc}
    */
   public function enable() {
-    return $this->storage->enable();
+    return $this->subject->enable();
   }
 
   /**
    * {@inheritdoc}
    */
   public function disable() {
-    return $this->storage->disable();
+    return $this->subject->disable();
   }
 
   /**
    * {@inheritdoc}
    */
   public function status() {
-    return $this->storage->status();
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getOriginalId() {
-    return $this->storage->getOriginalId();
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function setOriginalId($id) {
-    return $this->storage->setOriginalId($id);
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function preSave(EntityStorageInterface $storage) {
-    $this->storage->presave($storage);
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function postSave(EntityStorageInterface $storage, $update = TRUE) {
-    $this->storage->postSave($storage, $update);
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public static function preCreate(EntityStorageInterface $storage, array &$values) {
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function postCreate(EntityStorageInterface $storage) {
-    $this->storage->postCreate($storage);
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public static function preDelete(EntityStorageInterface $storage, array $entities) {
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public static function postDelete(EntityStorageInterface $storage, array $entities) {
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public static function postLoad(EntityStorageInterface $storage, array &$entities) {
+    return $this->subject->status();
   }
 
   /**
    * {@inheritdoc}
    */
   public function getExecutable() {
-    return $this->storage->getExecutable();
+    return $this->subject->getExecutable();
   }
 
   /**
    * {@inheritdoc}
    */
   public function duplicateDisplayAsType($old_display_id, $new_display_type) {
-    return $this->storage->duplicateDisplayAsType($old_display_id, $new_display_type);
+    return $this->subject->duplicateDisplayAsType($old_display_id, $new_display_type);
   }
 
   /**
    * {@inheritdoc}
    */
   public function mergeDefaultDisplaysOptions() {
-    $this->storage->mergeDefaultDisplaysOptions();
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function uriRelationships() {
-    return $this->storage->uriRelationships();
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function referencedEntities() {
-    return $this->storage->referencedEntities();
+    $this->subject->mergeDefaultDisplaysOptions();
   }
 
   /**
    * {@inheritdoc}
    */
   public function url($rel = 'edit-form', $options = []) {
-    return $this->storage->url($rel, $options);
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function hasLinkTemplate($key) {
-    return $this->storage->hasLinkTemplate($key);
+    return $this->subject->url($rel, $options);
   }
 
   /**
    * {@inheritdoc}
    */
   public function calculateDependencies() {
-    $this->storage->calculateDependencies();
+    $this->subject->calculateDependencies();
     return $this;
   }
 
-  /**
-   * {@inheritdoc}
-   */
-  public function getConfigDependencyKey() {
-    return $this->storage->getConfigDependencyKey();
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getConfigDependencyName() {
-    return $this->storage->getConfigDependencyName();
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getConfigTarget() {
-    return $this->storage->getConfigTarget();
-  }
-
   /**
    * {@inheritdoc}
    */
   public function onDependencyRemoval(array $dependencies) {
-    return $this->storage->onDependencyRemoval($dependencies);
+    return $this->subject->onDependencyRemoval($dependencies);
   }
 
   /**
    * {@inheritdoc}
    */
   public function getDependencies() {
-    return $this->storage->getDependencies();
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getCacheContexts() {
-    return $this->storage->getCacheContexts();
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getCacheTags() {
-    return $this->storage->getCacheTags();
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getCacheMaxAge() {
-    return $this->storage->getCacheMaxAge();
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getTypedData() {
-    $this->storage->getTypedData();
+    return $this->subject->getDependencies();
   }
 
   /**
    * {@inheritdoc}
    */
   public function addDisplay($plugin_id = 'page', $title = NULL, $id = NULL) {
-    return $this->storage->addDisplay($plugin_id, $title, $id);
+    return $this->subject->addDisplay($plugin_id, $title, $id);
   }
 
   /**
    * {@inheritdoc}
    */
   public function isInstallable() {
-    return $this->storage->isInstallable();
+    return $this->subject->isInstallable();
   }
 
   /**
    * {@inheritdoc}
    */
   public function setThirdPartySetting($module, $key, $value) {
-    return $this->storage->setThirdPartySetting($module, $key, $value);
+    return $this->subject->setThirdPartySetting($module, $key, $value);
   }
 
   /**
    * {@inheritdoc}
    */
   public function getThirdPartySetting($module, $key, $default = NULL) {
-    return $this->storage->getThirdPartySetting($module, $key, $default);
+    return $this->subject->getThirdPartySetting($module, $key, $default);
   }
 
   /**
    * {@inheritdoc}
    */
   public function getThirdPartySettings($module) {
-    return $this->storage->getThirdPartySettings($module);
+    return $this->subject->getThirdPartySettings($module);
   }
 
   /**
    * {@inheritdoc}
    */
   public function unsetThirdPartySetting($module, $key) {
-    return $this->storage->unsetThirdPartySetting($module, $key);
+    return $this->subject->unsetThirdPartySetting($module, $key);
   }
 
   /**
    * {@inheritdoc}
    */
   public function getThirdPartyProviders() {
-    return $this->storage->getThirdPartyProviders();
+    return $this->subject->getThirdPartyProviders();
   }
 
   /**
    * {@inheritdoc}
    */
   public function trustData() {
-    return $this->storage->trustData();
+    return $this->subject->trustData();
   }
 
   /**
    * {@inheritdoc}
    */
   public function hasTrustedData() {
-    return $this->storage->hasTrustedData();
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function addCacheableDependency($other_object) {
-    $this->storage->addCacheableDependency($other_object);
-    return $this;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function addCacheContexts(array $cache_contexts) {
-    return $this->storage->addCacheContexts($cache_contexts);
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function mergeCacheMaxAge($max_age) {
-    return $this->storage->mergeCacheMaxAge($max_age);
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getCacheTagsToInvalidate() {
-    return $this->storage->getCacheTagsToInvalidate();
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function addCacheTags(array $cache_tags) {
-    return $this->storage->addCacheTags($cache_tags);
+    return $this->subject->hasTrustedData();
   }
 
 }
