diff --git a/core/modules/comment/src/Plugin/views/field/EntityLink.php b/core/modules/comment/src/Plugin/views/field/EntityLink.php
index 9760057103..e51385876d 100644
--- a/core/modules/comment/src/Plugin/views/field/EntityLink.php
+++ b/core/modules/comment/src/Plugin/views/field/EntityLink.php
@@ -73,10 +73,12 @@ public function preRender(&$values) {
    * {@inheritdoc}
    */
   public function render(ResultRow $values) {
-    $entity = $this->getEntity($values);
-
     // Only render the links, if they are defined.
-    return !empty($this->build[$entity->id()]['links']['comment__comment']) ? \Drupal::service('renderer')->render($this->build[$entity->id()]['links']['comment__comment']) : '';
+    if ($entity = $this->getEntity($values)) {
+      return !empty($this->build[$entity->id()]['links']['comment__comment']) ? \Drupal::service('renderer')->render($this->build[$entity->id()]['links']['comment__comment']) : '';
+    }
+
+    return '';
   }
 
 }
diff --git a/core/modules/comment/src/Plugin/views/field/LinkApprove.php b/core/modules/comment/src/Plugin/views/field/LinkApprove.php
index 683c3cbb4c..0cd4734ee8 100644
--- a/core/modules/comment/src/Plugin/views/field/LinkApprove.php
+++ b/core/modules/comment/src/Plugin/views/field/LinkApprove.php
@@ -19,7 +19,9 @@ class LinkApprove extends LinkBase {
    * {@inheritdoc}
    */
   protected function getUrlInfo(ResultRow $row) {
-    return Url::fromRoute('comment.approve', ['comment' => $this->getEntity($row)->id()]);
+    if ($entity = $this->getEntity($row)) {
+      return Url::fromRoute('comment.approve', ['comment' => $entity->id()]);
+    }
   }
 
   /**
diff --git a/core/modules/comment/src/Plugin/views/field/LinkReply.php b/core/modules/comment/src/Plugin/views/field/LinkReply.php
index 3ddbd08152..5ab91cb9ee 100644
--- a/core/modules/comment/src/Plugin/views/field/LinkReply.php
+++ b/core/modules/comment/src/Plugin/views/field/LinkReply.php
@@ -20,13 +20,14 @@ class LinkReply extends LinkBase {
    */
   protected function getUrlInfo(ResultRow $row) {
     /** @var \Drupal\comment\CommentInterface $comment */
-    $comment = $this->getEntity($row);
-    return Url::fromRoute('comment.reply', [
-      'entity_type' => $comment->getCommentedEntityTypeId(),
-      'entity' => $comment->getCommentedEntityId(),
-      'field_name' => $comment->getFieldName(),
-      'pid' => $comment->id(),
-    ]);
+    if ($comment = $this->getEntity($row)) {
+      return Url::fromRoute('comment.reply', [
+        'entity_type' => $comment->getCommentedEntityTypeId(),
+        'entity' => $comment->getCommentedEntityId(),
+        'field_name' => $comment->getFieldName(),
+        'pid' => $comment->id(),
+      ]);
+    }
   }
 
   /**
diff --git a/core/modules/comment/tests/src/Unit/Plugin/views/field/EntityLinkTest.php b/core/modules/comment/tests/src/Unit/Plugin/views/field/EntityLinkTest.php
new file mode 100644
index 0000000000..4183b6c9d5
--- /dev/null
+++ b/core/modules/comment/tests/src/Unit/Plugin/views/field/EntityLinkTest.php
@@ -0,0 +1,31 @@
+<?php
+
+namespace Drupal\Tests\comment\Unit\Plugin\views\field;
+
+use Drupal\comment\Plugin\views\field\EntityLink;
+use Drupal\Tests\UnitTestCase;
+use Drupal\views\Plugin\views\display\DisplayPluginBase;
+use Drupal\views\ResultRow;
+use Drupal\views\ViewExecutable;
+
+/**
+ * @coversDefaultClass \Drupal\comment\Plugin\views\field\EntityLink
+ * @group comment
+ */
+class EntityLinkTest extends UnitTestCase {
+
+  /**
+   * Test the render method.
+   *
+   * @covers ::render
+   */
+  public function testRender() {
+    $row = new ResultRow();
+    $field = new EntityLink([], '', []);
+    $view = $this->createMock(ViewExecutable::class);
+    $display = $this->createMock(DisplayPluginBase::class);
+    $field->init($view, $display);
+    $this->assertEquals('', $field->render($row));
+  }
+
+}
\ No newline at end of file
diff --git a/core/modules/comment/tests/src/Unit/Plugin/views/field/LinkApproveTest.php b/core/modules/comment/tests/src/Unit/Plugin/views/field/LinkApproveTest.php
new file mode 100644
index 0000000000..f4f20fa08e
--- /dev/null
+++ b/core/modules/comment/tests/src/Unit/Plugin/views/field/LinkApproveTest.php
@@ -0,0 +1,47 @@
+<?php
+
+namespace Drupal\Tests\comment\Unit\Plugin\views\field;
+
+use Drupal\comment\Plugin\views\field\LinkApprove;
+use Drupal\Core\Access\AccessManagerInterface;
+use Drupal\Core\Entity\EntityRepositoryInterface;
+use Drupal\Core\Entity\EntityTypeManagerInterface;
+use Drupal\Core\Language\LanguageManagerInterface;
+use Drupal\Core\StringTranslation\TranslationInterface;
+use Drupal\Tests\UnitTestCase;
+use Drupal\views\Plugin\views\display\DisplayPluginBase;
+use Drupal\views\ResultRow;
+use Drupal\views\ViewExecutable;
+use Symfony\Component\DependencyInjection\ContainerBuilder;
+
+/**
+ * @coversDefaultClass \Drupal\comment\Plugin\views\field\LinkApprove
+ * @group comment
+ */
+class LinkApproveTest extends UnitTestCase {
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function tearDown() {
+    parent::tearDown();
+    $container = new \Drupal\Core\DependencyInjection\ContainerBuilder();
+    \Drupal::setContainer($container);
+  }
+
+  /**
+   * Tests the render method.
+   */
+  public function testRender() {
+    $row = new ResultRow();
+    $container = new ContainerBuilder();
+    $container->set('string_translation', $this->createMock(TranslationInterface::class));
+    \Drupal::setContainer($container);
+    $field = new LinkApprove([], '', [], $this->createMock(AccessManagerInterface::class), $this->createMock(EntityTypeManagerInterface::class), $this->createMock(EntityRepositoryInterface::class), $this->createMock(LanguageManagerInterface::class));
+    $view = $this->createMock(ViewExecutable::class);
+    $display = $this->createMock(DisplayPluginBase::class);
+    $field->init($view, $display);
+    $this->assertEquals('', $field->render($row));
+  }
+
+}
\ No newline at end of file
diff --git a/core/modules/comment/tests/src/Unit/Plugin/views/field/LinkReplyTest.php b/core/modules/comment/tests/src/Unit/Plugin/views/field/LinkReplyTest.php
new file mode 100644
index 0000000000..0cbe8557b9
--- /dev/null
+++ b/core/modules/comment/tests/src/Unit/Plugin/views/field/LinkReplyTest.php
@@ -0,0 +1,47 @@
+<?php
+
+namespace Drupal\Tests\comment\Unit\Plugin\views\field;
+
+use Drupal\comment\Plugin\views\field\LinkReply;
+use Drupal\Core\Access\AccessManagerInterface;
+use Drupal\Core\Entity\EntityRepositoryInterface;
+use Drupal\Core\Entity\EntityTypeManagerInterface;
+use Drupal\Core\Language\LanguageManagerInterface;
+use Drupal\Core\StringTranslation\TranslationInterface;
+use Drupal\Tests\UnitTestCase;
+use Drupal\views\Plugin\views\display\DisplayPluginBase;
+use Drupal\views\ResultRow;
+use Drupal\views\ViewExecutable;
+use Symfony\Component\DependencyInjection\ContainerBuilder;
+
+/**
+ * @coversDefaultClass \Drupal\comment\Plugin\views\field\LinkReply
+ * @group comment
+ */
+class LinkReplyTest extends UnitTestCase {
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function tearDown() {
+    parent::tearDown();
+    $container = new \Drupal\Core\DependencyInjection\ContainerBuilder();
+    \Drupal::setContainer($container);
+  }
+
+  /**
+   * Tests the render method.
+   */
+  public function testRender() {
+    $row = new ResultRow();
+    $container = new ContainerBuilder();
+    $container->set('string_translation', $this->createMock(TranslationInterface::class));
+    \Drupal::setContainer($container);
+    $field = new LinkReply([], '', [], $this->createMock(AccessManagerInterface::class), $this->createMock(EntityTypeManagerInterface::class), $this->createMock(EntityRepositoryInterface::class), $this->createMock(LanguageManagerInterface::class));
+    $view = $this->createMock(ViewExecutable::class);
+    $display = $this->createMock(DisplayPluginBase::class);
+    $field->init($view, $display);
+    $this->assertEquals('', $field->render($row));
+  }
+
+}
\ No newline at end of file
diff --git a/core/modules/contact/src/Plugin/views/field/ContactLink.php b/core/modules/contact/src/Plugin/views/field/ContactLink.php
index a98be137dd..b2f9e66c10 100644
--- a/core/modules/contact/src/Plugin/views/field/ContactLink.php
+++ b/core/modules/contact/src/Plugin/views/field/ContactLink.php
@@ -30,14 +30,18 @@ public function buildOptionsForm(&$form, FormStateInterface $form_state) {
    * {@inheritdoc}
    */
   protected function getUrlInfo(ResultRow $row) {
-    return Url::fromRoute('entity.user.contact_form', ['user' => $this->getEntity($row)->id()]);
+    if ($entity = $this->getEntity($row)) {
+      return Url::fromRoute('entity.user.contact_form', ['user' => $entity->id()]);
+    }
   }
 
   /**
    * {@inheritdoc}
    */
   protected function renderLink(ResultRow $row) {
-    $entity = $this->getEntity($row);
+    if (!$entity = $this->getEntity($row)) {
+      return '';
+    }
 
     $this->options['alter']['make_link'] = TRUE;
     $this->options['alter']['url'] = $this->getUrlInfo($row);
diff --git a/core/modules/contact/tests/src/Unit/ContactLinkTest.php b/core/modules/contact/tests/src/Unit/ContactLinkTest.php
new file mode 100644
index 0000000000..98e6953441
--- /dev/null
+++ b/core/modules/contact/tests/src/Unit/ContactLinkTest.php
@@ -0,0 +1,47 @@
+<?php
+
+namespace Drupal\Tests\contact\Unit;
+
+use Drupal\contact\Plugin\views\field\ContactLink;
+use Drupal\Core\Access\AccessManagerInterface;
+use Drupal\Core\Entity\EntityRepositoryInterface;
+use Drupal\Core\Entity\EntityTypeManagerInterface;
+use Drupal\Core\Language\LanguageManagerInterface;
+use Drupal\Core\StringTranslation\TranslationInterface;
+use Drupal\Tests\UnitTestCase;
+use Drupal\views\Plugin\views\display\DisplayPluginBase;
+use Drupal\views\ResultRow;
+use Drupal\views\ViewExecutable;
+use Symfony\Component\DependencyInjection\ContainerBuilder;
+
+/**
+ * @coversDefaultClass \Drupal\contact\Plugin\views\field\ContactLink
+ * @group contact
+ */
+class ContactLinkTest extends UnitTestCase {
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function tearDown() {
+    parent::tearDown();
+    $container = new \Drupal\Core\DependencyInjection\ContainerBuilder();
+    \Drupal::setContainer($container);
+  }
+
+  /**
+   * Tests the render method.
+   */
+  public function testRender() {
+    $row = new ResultRow();
+    $container = new ContainerBuilder();
+    $container->set('string_translation', $this->createMock(TranslationInterface::class));
+    \Drupal::setContainer($container);
+    $field = new ContactLink([], '', [], $this->createMock(AccessManagerInterface::class), $this->createMock(EntityTypeManagerInterface::class), $this->createMock(EntityRepositoryInterface::class), $this->createMock(LanguageManagerInterface::class));
+    $view = $this->createMock(ViewExecutable::class);
+    $display = $this->createMock(DisplayPluginBase::class);
+    $field->init($view, $display);
+    $this->assertEquals('', $field->render($row));
+  }
+
+}
\ No newline at end of file
diff --git a/core/modules/media_library/media_library.module b/core/modules/media_library/media_library.module
index 860035e72b..10b63adb02 100644
--- a/core/modules/media_library/media_library.module
+++ b/core/modules/media_library/media_library.module
@@ -138,7 +138,10 @@ function media_library_form_views_form_media_library_page_alter(array &$form, Fo
     $view = $form['output'][0]['#view'];
     foreach (Element::getVisibleChildren($form['media_bulk_form']) as $key) {
       if (isset($view->result[$key])) {
-        $media = $view->field['media_bulk_form']->getEntity($view->result[$key]);
+        if (!$media = $view->field['media_bulk_form']->getEntity($view->result[$key])) {
+          $form['media_bulk_form'][$key]['#title'] = '';
+          continue;
+        }
         $form['media_bulk_form'][$key]['#title'] = t('Select @label', [
           '@label' => $media->label(),
         ]);
diff --git a/core/modules/media_library/media_library.module.orig b/core/modules/media_library/media_library.module.orig
new file mode 100644
index 0000000000..860035e72b
--- /dev/null
+++ b/core/modules/media_library/media_library.module.orig
@@ -0,0 +1,416 @@
+<?php
+
+/**
+ * @file
+ * Contains hook implementations for the media_library module.
+ */
+
+use Drupal\Component\Utility\UrlHelper;
+use Drupal\Core\Access\AccessResult;
+use Drupal\Core\Entity\EntityInterface;
+use Drupal\Core\Entity\Entity\EntityFormDisplay;
+use Drupal\Core\Entity\Entity\EntityViewDisplay;
+use Drupal\Core\Field\Plugin\Field\FieldType\EntityReferenceItem;
+use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\Render\Element;
+use Drupal\Core\Routing\RouteMatchInterface;
+use Drupal\Core\Session\AccountInterface;
+use Drupal\Core\Template\Attribute;
+use Drupal\image\Entity\ImageStyle;
+use Drupal\image\Plugin\Field\FieldType\ImageItem;
+use Drupal\media\MediaTypeForm;
+use Drupal\media\MediaTypeInterface;
+use Drupal\media_library\Form\FileUploadForm;
+use Drupal\media_library\Form\OEmbedForm;
+use Drupal\media_library\MediaLibraryState;
+use Drupal\views\Form\ViewsForm;
+use Drupal\views\Plugin\views\cache\CachePluginBase;
+use Drupal\views\ViewExecutable;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
+use Drupal\Component\Serialization\Json;
+
+/**
+ * Implements hook_help().
+ *
+ * @todo Update in https://www.drupal.org/project/drupal/issues/2964789
+ */
+function media_library_help($route_name, RouteMatchInterface $route_match) {
+  switch ($route_name) {
+    case 'help.page.media_library':
+      $output = '<h3>' . t('About') . '</h3>';
+      $output .= '<p>' . t('The Media Library module overrides the /admin/content/media view to provide a rich visual interface for performing administrative operations on media. For more information, see the <a href=":media">online documentation for the Media Library module</a>.', [':media' => 'https://www.drupal.org/docs/8/core/modules/media']) . '</p>';
+      return $output;
+  }
+}
+
+/**
+ * Implements hook_media_source_info_alter().
+ */
+function media_library_media_source_info_alter(array &$sources) {
+  $sources['audio_file']['forms']['media_library_add'] = FileUploadForm::class;
+  $sources['file']['forms']['media_library_add'] = FileUploadForm::class;
+  $sources['image']['forms']['media_library_add'] = FileUploadForm::class;
+  $sources['video_file']['forms']['media_library_add'] = FileUploadForm::class;
+  $sources['oembed:video']['forms']['media_library_add'] = OEmbedForm::class;
+}
+
+/**
+ * Implements hook_theme().
+ */
+function media_library_theme() {
+  return [
+    'media__media_library' => [
+      'base hook' => 'media',
+    ],
+  ];
+}
+
+/**
+ * Implements hook_views_post_render().
+ */
+function media_library_views_post_render(ViewExecutable $view, &$output, CachePluginBase $cache) {
+  if ($view->id() === 'media_library') {
+    $output['#attached']['library'][] = 'media_library/view';
+    if (strpos($view->current_display, 'widget') === 0) {
+      try {
+        $query = MediaLibraryState::fromRequest($view->getRequest())->all();
+      }
+      catch (InvalidArgumentException $e) {
+        // MediaLibraryState::fromRequest() will throw an exception if the view
+        // is being previewed, since not all required query parameters will be
+        // present. In a preview, however, this can be omitted since we're
+        // merely previewing.
+        // @todo Use the views API for checking for the preview mode when it
+        //   lands. https://www.drupal.org/project/drupal/issues/3060855
+        if (empty($view->preview) && empty($view->live_preview)) {
+          throw $e;
+        }
+      }
+
+      // If the current query contains any parameters we use to contextually
+      // filter the view, ensure they persist across AJAX rebuilds.
+      // The ajax_path is shared for all AJAX views on the page, but our query
+      // parameters are prefixed and should not interfere with any other views.
+      // @todo Rework or remove this in https://www.drupal.org/node/2983451
+      if (!empty($query)) {
+        $ajax_path = &$output['#attached']['drupalSettings']['views']['ajax_path'];
+        $parsed_url = UrlHelper::parse($ajax_path);
+        $query = array_merge($query, $parsed_url['query']);
+        $ajax_path = $parsed_url['path'] . '?' . UrlHelper::buildQuery($query);
+      }
+    }
+  }
+}
+
+/**
+ * Implements hook_preprocess_media().
+ */
+function media_library_preprocess_media(&$variables) {
+  if ($variables['view_mode'] === 'media_library') {
+    /** @var \Drupal\media\MediaInterface $media */
+    $media = $variables['media'];
+    $variables['#cache']['contexts'][] = 'user.permissions';
+    $rel = $media->access('edit') ? 'edit-form' : 'canonical';
+    $variables['url'] = $media->toUrl($rel, [
+      'language' => $media->language(),
+    ]);
+    $variables['preview_attributes'] = new Attribute();
+    $variables['preview_attributes']->addClass('media-library-item__preview', 'js-media-library-item-preview', 'js-click-to-select-trigger');
+    $variables['metadata_attributes'] = new Attribute();
+    $variables['metadata_attributes']->addClass('media-library-item__attributes');
+    $variables['status'] = $media->isPublished();
+  }
+}
+
+/**
+ * Alter the bulk form to add a more accessible label.
+ *
+ * @param array $form
+ *   An associative array containing the structure of the form.
+ * @param \Drupal\Core\Form\FormStateInterface $form_state
+ *   The current state of the form.
+ *
+ * @todo Remove in https://www.drupal.org/node/2983454
+ */
+function media_library_form_views_form_media_library_page_alter(array &$form, FormStateInterface $form_state) {
+  if (isset($form['media_bulk_form']) && isset($form['output'])) {
+    /** @var \Drupal\views\ViewExecutable $view */
+    $view = $form['output'][0]['#view'];
+    foreach (Element::getVisibleChildren($form['media_bulk_form']) as $key) {
+      if (isset($view->result[$key])) {
+        $media = $view->field['media_bulk_form']->getEntity($view->result[$key]);
+        $form['media_bulk_form'][$key]['#title'] = t('Select @label', [
+          '@label' => $media->label(),
+        ]);
+      }
+    }
+  }
+}
+
+/**
+ * Implements hook_form_alter().
+ */
+function media_library_form_alter(array &$form, FormStateInterface $form_state, $form_id) {
+  $form_object = $form_state->getFormObject();
+  if ($form_object instanceof ViewsForm && strpos($form_object->getBaseFormId(), 'views_form_media_library') === 0) {
+    $form['#attributes']['class'][] = 'media-library-views-form';
+    if (isset($form['header'])) {
+      $form['header']['#attributes']['class'][] = 'media-library-views-form__header';
+      $form['header']['media_bulk_form']['#attributes']['class'][] = 'media-library-views-form__bulk_form';
+    }
+  }
+
+  // Add after build to fix media library views exposed filter's submit button.
+  if ($form_id === 'views_exposed_form' && strpos($form['#id'], 'views-exposed-form-media-library-widget') === 0) {
+    $form['#after_build'][] = '_media_library_views_form_media_library_after_build';
+  }
+
+  // Configures media_library displays when a type is submitted.
+  if ($form_object instanceof MediaTypeForm) {
+    $form['actions']['submit']['#submit'][] = '_media_library_media_type_form_submit';
+  }
+}
+
+/**
+ * After build callback for views form media library.
+ */
+function _media_library_views_form_media_library_after_build(array $form, FormStateInterface $form_state) {
+  // Remove .form-actions from media library views exposed filter actions
+  // and replace with .media-library-view--form-actions.
+  //
+  // This prevents the views exposed filter's 'Apply filter' submit button from
+  // being moved into the dialog's buttons.
+  // @see \Drupal\Core\Render\Element\Actions::processActions
+  // @see Drupal.behaviors.dialog.prepareDialogButtons
+  if (($key = array_search('form-actions', $form['actions']['#attributes']['class'])) !== FALSE) {
+    unset($form['actions']['#attributes']['class'][$key]);
+  }
+  $form['actions']['#attributes']['class'][] = 'media-library-view--form-actions';
+  return $form;
+}
+
+/**
+ * Submit callback for media type form.
+ */
+function _media_library_media_type_form_submit(array &$form, FormStateInterface $form_state) {
+  $form_object = $form_state->getFormObject();
+  if ($form_object->getOperation() === 'add') {
+    $type = $form_object->getEntity();
+    $form_display_created = _media_library_configure_form_display($type);
+    $view_display_created = _media_library_configure_view_display($type);
+    if ($form_display_created || $view_display_created) {
+      \Drupal::messenger()->addStatus(t('Media Library form and view displays have been created for the %type media type.', [
+        '%type' => $type->label(),
+      ]));
+    }
+  }
+}
+
+/**
+ * Implements hook_field_ui_preconfigured_options_alter().
+ */
+function media_library_field_ui_preconfigured_options_alter(array &$options, $field_type) {
+  // If the field is not an "entity_reference"-based field, bail out.
+  $class = \Drupal::service('plugin.manager.field.field_type')->getPluginClass($field_type);
+  if (!is_a($class, EntityReferenceItem::class, TRUE)) {
+    return;
+  }
+
+  // Set the default field widget for media to be the Media library.
+  if (!empty($options['media'])) {
+    $options['media']['entity_form_display']['type'] = 'media_library_widget';
+  }
+}
+
+/**
+ * Implements hook_local_tasks_alter().
+ *
+ * Removes tasks for the Media library if the view display no longer exists.
+ */
+function media_library_local_tasks_alter(&$local_tasks) {
+  /** @var \Symfony\Component\Routing\RouteCollection $route_collection */
+  $route_collection = \Drupal::service('router')->getRouteCollection();
+  foreach (['media_library.grid', 'media_library.table'] as $key) {
+    if (isset($local_tasks[$key]) && !$route_collection->get($local_tasks[$key]['route_name'])) {
+      unset($local_tasks[$key]);
+    }
+  }
+}
+
+/**
+ * Implements hook_ENTITY_TYPE_access().
+ */
+function media_library_image_style_access(EntityInterface $entity, $operation, AccountInterface $account) {
+  // Prevent the fallback 'media_library' image style from being deleted.
+  // @todo: Lock the image style instead of preventing delete access.
+  //   https://www.drupal.org/project/drupal/issues/2247293
+  if ($operation === 'delete' && $entity->id() === 'media_library') {
+    return AccessResult::forbidden();
+  }
+}
+
+/**
+ * Ensures that the given media type has a media_library form display.
+ *
+ * @param \Drupal\media\MediaTypeInterface $type
+ *   The media type to configure.
+ *
+ * @return bool
+ *   Whether a form display has been created or not.
+ *
+ * @throws \Drupal\Core\Entity\EntityStorageException
+ */
+function _media_library_configure_form_display(MediaTypeInterface $type) {
+  $display = EntityFormDisplay::load('media.' . $type->id() . '.media_library');
+
+  if ($display) {
+    return FALSE;
+  }
+
+  $values = [
+    'targetEntityType' => 'media',
+    'bundle' => $type->id(),
+    'mode' => 'media_library',
+    'status' => TRUE,
+  ];
+  $display = EntityFormDisplay::create($values);
+  // Remove all default components.
+  foreach (array_keys($display->getComponents()) as $name) {
+    $display->removeComponent($name);
+  }
+  // Expose the name field when it is not mapped.
+  $field_map = $type->getFieldMap();
+  if (empty($field_map['name'])) {
+    $display->setComponent('name', [
+      'type' => 'string_textfield',
+      'settings' => [
+        'size' => 60,
+      ],
+    ]);
+  }
+  // If the source field is an image field, expose it so that users can set alt
+  // and title text.
+  $source_field = $type->getSource()->getSourceFieldDefinition($type);
+  if ($source_field->isDisplayConfigurable('form') && is_a($source_field->getItemDefinition()->getClass(), ImageItem::class, TRUE)) {
+    $type->getSource()->prepareFormDisplay($type, $display);
+  }
+  return (bool) $display->save();
+}
+
+/**
+ * Ensures that the given media type has a media_library view display.
+ *
+ * @param \Drupal\media\MediaTypeInterface $type
+ *   The media type to configure.
+ *
+ * @return bool
+ *   Whether a view display has been created or not.
+ *
+ * @throws \Drupal\Core\Entity\EntityStorageException
+ */
+function _media_library_configure_view_display(MediaTypeInterface $type) {
+  $display = EntityViewDisplay::load('media.' . $type->id() . '.media_library');
+
+  if ($display) {
+    return FALSE;
+  }
+
+  $values = [
+    'targetEntityType' => 'media',
+    'bundle' => $type->id(),
+    'mode' => 'media_library',
+    'status' => TRUE,
+  ];
+  $display = EntityViewDisplay::create($values);
+  // Remove all default components.
+  foreach (array_keys($display->getComponents()) as $name) {
+    $display->removeComponent($name);
+  }
+
+  // @todo: Remove dependency on 'medium' and 'thumbnail' image styles from
+  //   media and media library modules.
+  //   https://www.drupal.org/project/drupal/issues/3030437
+  $image_style = ImageStyle::load('medium');
+
+  // Expose the thumbnail component. If the medium image style doesn't exist,
+  // use the fallback 'media_library' image style.
+  $display->setComponent('thumbnail', [
+    'type' => 'image',
+    'label' => 'hidden',
+    'settings' => [
+      'image_style' => $image_style ? $image_style->id() : 'media_library',
+      'image_link' => '',
+    ],
+  ]);
+  return (bool) $display->save();
+}
+
+/**
+ * Implements hook_form_FORM_ID_alter().
+ */
+function media_library_form_filter_format_edit_form_alter(array &$form, FormStateInterface $form_state, $form_id) {
+  // Add an additional validate callback so so we can ensure the media_embed
+  // filter is enabled when the DrupalMediaLibrary button is enabled.
+  $form['#validate'][] = 'media_library_filter_format_edit_form_validate';
+}
+
+/**
+ * Implements hook_form_FORM_ID_alter().
+ */
+function media_library_form_filter_format_add_form_alter(array &$form, FormStateInterface $form_state, $form_id) {
+  // Add an additional validate callback so so we can ensure the media_embed
+  // filter is enabled when the DrupalMediaLibrary button is enabled.
+  $form['#validate'][] = 'media_library_filter_format_edit_form_validate';
+}
+
+/**
+ * Validate callback to ensure the DrupalMediaLibrary button can work correctly.
+ */
+function media_library_filter_format_edit_form_validate($form, FormStateInterface $form_state) {
+  if ($form_state->getTriggeringElement()['#name'] !== 'op') {
+    return;
+  }
+
+  // The "DrupalMediaLibrary" button is for the CKEditor text editor.
+  if ($form_state->getValue(['editor', 'editor']) !== 'ckeditor') {
+    return;
+  }
+
+  $button_group_path = [
+    'editor',
+    'settings',
+    'toolbar',
+    'button_groups',
+  ];
+
+  if ($button_groups = $form_state->getValue($button_group_path)) {
+    $buttons = [];
+    $button_groups = Json::decode($button_groups);
+
+    foreach ($button_groups as $button_row) {
+      foreach ($button_row as $button_group) {
+        $buttons = array_merge($buttons, array_values($button_group['items']));
+      }
+    }
+
+    $get_filter_label = function ($filter_plugin_id) use ($form) {
+      return (string) $form['filters']['order'][$filter_plugin_id]['filter']['#markup'];
+    };
+
+    if (in_array('DrupalMediaLibrary', $buttons, TRUE)) {
+      $media_embed_enabled = $form_state->getValue([
+        'filters',
+        'media_embed',
+        'status',
+      ]);
+
+      if (!$media_embed_enabled) {
+        $error_message = new TranslatableMarkup('The %media-embed-filter-label filter must be enabled to use the %drupal-media-library-button button.', [
+          '%media-embed-filter-label' => $get_filter_label('media_embed'),
+          '%drupal-media-library-button' => new TranslatableMarkup('Insert from Media Library'),
+        ]);
+        $form_state->setErrorByName('filters', $error_message);
+      }
+    }
+  }
+}
diff --git a/core/modules/media_library/src/Plugin/views/field/MediaLibrarySelectForm.php b/core/modules/media_library/src/Plugin/views/field/MediaLibrarySelectForm.php
index fcb8627ba7..1f3beb7749 100644
--- a/core/modules/media_library/src/Plugin/views/field/MediaLibrarySelectForm.php
+++ b/core/modules/media_library/src/Plugin/views/field/MediaLibrarySelectForm.php
@@ -54,7 +54,10 @@ public function viewsForm(array &$form, FormStateInterface $form_state) {
     // Render checkboxes for all rows.
     $form[$this->options['id']]['#tree'] = TRUE;
     foreach ($this->view->result as $row_index => $row) {
-      $entity = $this->getEntity($row);
+      if (!$entity = $this->getEntity($row)) {
+        $form[$this->options['id']][$row_index] = [];
+        continue;
+      }
       $form[$this->options['id']][$row_index] = [
         '#type' => 'checkbox',
         '#title' => $this->t('Select @label', [
diff --git a/core/modules/media_library/tests/src/Unit/MediaLibrarySelectFormTest.php b/core/modules/media_library/tests/src/Unit/MediaLibrarySelectFormTest.php
new file mode 100644
index 0000000000..f22bdd975f
--- /dev/null
+++ b/core/modules/media_library/tests/src/Unit/MediaLibrarySelectFormTest.php
@@ -0,0 +1,36 @@
+<?php
+
+namespace Drupal\Tests\media_library\Unit;
+
+use Drupal\Core\Form\FormStateInterface;
+use Drupal\media_library\Plugin\views\field\MediaLibrarySelectForm;
+use Drupal\Tests\UnitTestCase;
+use Drupal\views\Plugin\views\display\DisplayPluginBase;
+use Drupal\views\ResultRow;
+use Drupal\views\ViewExecutable;
+
+/**
+ * @coversDefaultClass \Drupal\media_library\Plugin\views\field\MediaLibrarySelectForm
+ * @group media_library
+ */
+class MediaLibrarySelectFormTest extends UnitTestCase {
+
+  /**
+   * Tests the viewsForm method.
+   *
+   * @covers ::viewsForm
+   */
+  public function testViewsForm() {
+    $row = new ResultRow();
+    $field = new MediaLibrarySelectForm([], '', []);
+    $view = $this->createMock(ViewExecutable::class);
+    $display = $this->createMock(DisplayPluginBase::class);
+    $form_state = $this->createMock(FormStateInterface::class);
+    $view->result = [$row];
+    $field->init($view, $display);
+    $form = [];
+    $field->viewsForm($form, $form_state);
+    $this->assertNotEmpty($form);
+  }
+
+}
\ No newline at end of file
diff --git a/core/modules/node/src/Plugin/views/field/RevisionLink.php b/core/modules/node/src/Plugin/views/field/RevisionLink.php
index 949ad6e07c..e6ca12a464 100644
--- a/core/modules/node/src/Plugin/views/field/RevisionLink.php
+++ b/core/modules/node/src/Plugin/views/field/RevisionLink.php
@@ -20,11 +20,15 @@ class RevisionLink extends LinkBase {
    */
   protected function getUrlInfo(ResultRow $row) {
     /** @var \Drupal\node\NodeInterface $node */
-    $node = $this->getEntity($row);
-    // Current revision uses the node view path.
-    return !$node->isDefaultRevision() ?
-      Url::fromRoute('entity.node.revision', ['node' => $node->id(), 'node_revision' => $node->getRevisionId()]) :
-      $node->toUrl();
+    if ($node = $this->getEntity($row)) {
+      // Current revision uses the node view path.
+      return !$node->isDefaultRevision() ?
+        Url::fromRoute('entity.node.revision', [
+          'node' => $node->id(),
+          'node_revision' => $node->getRevisionId()
+        ]) :
+        $node->toUrl();
+    }
   }
 
   /**
@@ -33,7 +37,7 @@ protected function getUrlInfo(ResultRow $row) {
   protected function renderLink(ResultRow $row) {
     /** @var \Drupal\node\NodeInterface $node */
     $node = $this->getEntity($row);
-    if (!$node->getRevisionid()) {
+    if (!$node || !$node->getRevisionid()) {
       return '';
     }
     $text = parent::renderLink($row);
diff --git a/core/modules/node/src/Plugin/views/field/RevisionLinkDelete.php b/core/modules/node/src/Plugin/views/field/RevisionLinkDelete.php
index 2e1f683b52..301658ad9f 100644
--- a/core/modules/node/src/Plugin/views/field/RevisionLinkDelete.php
+++ b/core/modules/node/src/Plugin/views/field/RevisionLinkDelete.php
@@ -19,8 +19,12 @@ class RevisionLinkDelete extends RevisionLink {
    */
   protected function getUrlInfo(ResultRow $row) {
     /** @var \Drupal\node\NodeInterface $node */
-    $node = $this->getEntity($row);
-    return Url::fromRoute('node.revision_delete_confirm', ['node' => $node->id(), 'node_revision' => $node->getRevisionId()]);
+    if ($node = $this->getEntity($row)) {
+      return Url::fromRoute('node.revision_delete_confirm', [
+        'node' => $node->id(),
+        'node_revision' => $node->getRevisionId(),
+      ]);
+    }
   }
 
   /**
diff --git a/core/modules/node/src/Plugin/views/field/RevisionLinkRevert.php b/core/modules/node/src/Plugin/views/field/RevisionLinkRevert.php
index 33b20b8885..5b40a2b12f 100644
--- a/core/modules/node/src/Plugin/views/field/RevisionLinkRevert.php
+++ b/core/modules/node/src/Plugin/views/field/RevisionLinkRevert.php
@@ -19,8 +19,12 @@ class RevisionLinkRevert extends RevisionLink {
    */
   protected function getUrlInfo(ResultRow $row) {
     /** @var \Drupal\node\NodeInterface $node */
-    $node = $this->getEntity($row);
-    return Url::fromRoute('node.revision_revert_confirm', ['node' => $node->id(), 'node_revision' => $node->getRevisionId()]);
+    if ($node = $this->getEntity($row)) {
+      return Url::fromRoute('node.revision_revert_confirm', [
+        'node' => $node->id(),
+        'node_revision' => $node->getRevisionId()
+      ]);
+    }
   }
 
   /**
diff --git a/core/modules/node/tests/src/Unit/Plugin/views/field/RevisionLinkDeleteTest.php b/core/modules/node/tests/src/Unit/Plugin/views/field/RevisionLinkDeleteTest.php
new file mode 100644
index 0000000000..5ec16dc1e4
--- /dev/null
+++ b/core/modules/node/tests/src/Unit/Plugin/views/field/RevisionLinkDeleteTest.php
@@ -0,0 +1,48 @@
+<?php
+
+namespace Drupal\Tests\node\Unit\Plugin\views\field;
+
+use Drupal\Core\Access\AccessManagerInterface;
+use Drupal\Core\Entity\EntityRepositoryInterface;
+use Drupal\Core\Entity\EntityTypeManagerInterface;
+use Drupal\Core\Language\LanguageManagerInterface;
+use Drupal\Core\StringTranslation\TranslationInterface;
+use Drupal\node\Plugin\views\field\RevisionLink;
+use Drupal\node\Plugin\views\field\RevisionLinkDelete;
+use Drupal\Tests\UnitTestCase;
+use Drupal\views\Plugin\views\display\DisplayPluginBase;
+use Drupal\views\ResultRow;
+use Drupal\views\ViewExecutable;
+use Symfony\Component\DependencyInjection\ContainerBuilder;
+
+/**
+ * @coversDefaultClass \Drupal\node\Plugin\views\field\RevisionLinkDelete
+ * @group node
+ */
+class RevisionLinkDeleteTest extends UnitTestCase {
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function tearDown() {
+    parent::tearDown();
+    $container = new \Drupal\Core\DependencyInjection\ContainerBuilder();
+    \Drupal::setContainer($container);
+  }
+
+  /**
+   * Tests the render method.
+   */
+  public function testRender() {
+    $row = new ResultRow();
+    $container = new ContainerBuilder();
+    $container->set('string_translation', $this->createMock(TranslationInterface::class));
+    \Drupal::setContainer($container);
+    $field = new RevisionLinkDelete([], '', [], $this->createMock(AccessManagerInterface::class), $this->createMock(EntityTypeManagerInterface::class), $this->createMock(EntityRepositoryInterface::class), $this->createMock(LanguageManagerInterface::class));
+    $view = $this->createMock(ViewExecutable::class);
+    $display = $this->createMock(DisplayPluginBase::class);
+    $field->init($view, $display);
+    $this->assertEquals('', $field->render($row));
+  }
+
+}
diff --git a/core/modules/node/tests/src/Unit/Plugin/views/field/RevisionLinkRevertTest.php b/core/modules/node/tests/src/Unit/Plugin/views/field/RevisionLinkRevertTest.php
new file mode 100644
index 0000000000..c07d5cf8df
--- /dev/null
+++ b/core/modules/node/tests/src/Unit/Plugin/views/field/RevisionLinkRevertTest.php
@@ -0,0 +1,48 @@
+<?php
+
+namespace Drupal\Tests\node\Unit\Plugin\views\field;
+
+use Drupal\Core\Access\AccessManagerInterface;
+use Drupal\Core\Entity\EntityRepositoryInterface;
+use Drupal\Core\Entity\EntityTypeManagerInterface;
+use Drupal\Core\Language\LanguageManagerInterface;
+use Drupal\Core\StringTranslation\TranslationInterface;
+use Drupal\node\Plugin\views\field\RevisionLink;
+use Drupal\node\Plugin\views\field\RevisionLinkDelete;
+use Drupal\Tests\UnitTestCase;
+use Drupal\views\Plugin\views\display\DisplayPluginBase;
+use Drupal\views\ResultRow;
+use Drupal\views\ViewExecutable;
+use Symfony\Component\DependencyInjection\ContainerBuilder;
+
+/**
+ * @coversDefaultClass \Drupal\node\Plugin\views\field\RevisionLinkRevert
+ * @group node
+ */
+class RevisionLinkRevertTest extends UnitTestCase {
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function tearDown() {
+    parent::tearDown();
+    $container = new \Drupal\Core\DependencyInjection\ContainerBuilder();
+    \Drupal::setContainer($container);
+  }
+
+  /**
+   * Tests the render method.
+   */
+  public function testRender() {
+    $row = new ResultRow();
+    $container = new ContainerBuilder();
+    $container->set('string_translation', $this->createMock(TranslationInterface::class));
+    \Drupal::setContainer($container);
+    $field = new RevisionLinkDelete([], '', [], $this->createMock(AccessManagerInterface::class), $this->createMock(EntityTypeManagerInterface::class), $this->createMock(EntityRepositoryInterface::class), $this->createMock(LanguageManagerInterface::class));
+    $view = $this->createMock(ViewExecutable::class);
+    $display = $this->createMock(DisplayPluginBase::class);
+    $field->init($view, $display);
+    $this->assertEquals('', $field->render($row));
+  }
+
+}
diff --git a/core/modules/node/tests/src/Unit/Plugin/views/field/RevisionLinkTest.php b/core/modules/node/tests/src/Unit/Plugin/views/field/RevisionLinkTest.php
new file mode 100644
index 0000000000..5e0c5bae24
--- /dev/null
+++ b/core/modules/node/tests/src/Unit/Plugin/views/field/RevisionLinkTest.php
@@ -0,0 +1,47 @@
+<?php
+
+namespace Drupal\Tests\node\Unit\Plugin\views\field;
+
+use Drupal\Core\Access\AccessManagerInterface;
+use Drupal\Core\Entity\EntityRepositoryInterface;
+use Drupal\Core\Entity\EntityTypeManagerInterface;
+use Drupal\Core\Language\LanguageManagerInterface;
+use Drupal\Core\StringTranslation\TranslationInterface;
+use Drupal\node\Plugin\views\field\RevisionLink;
+use Drupal\Tests\UnitTestCase;
+use Drupal\views\Plugin\views\display\DisplayPluginBase;
+use Drupal\views\ResultRow;
+use Drupal\views\ViewExecutable;
+use Symfony\Component\DependencyInjection\ContainerBuilder;
+
+/**
+ * @coversDefaultClass \Drupal\node\Plugin\views\field\RevisionLink
+ * @group node
+ */
+class RevisionLinkTest extends UnitTestCase {
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function tearDown() {
+    parent::tearDown();
+    $container = new \Drupal\Core\DependencyInjection\ContainerBuilder();
+    \Drupal::setContainer($container);
+  }
+
+  /**
+   * Tests the render method.
+   */
+  public function testRender() {
+    $row = new ResultRow();
+    $container = new ContainerBuilder();
+    $container->set('string_translation', $this->createMock(TranslationInterface::class));
+    \Drupal::setContainer($container);
+    $field = new RevisionLink([], '', [], $this->createMock(AccessManagerInterface::class), $this->createMock(EntityTypeManagerInterface::class), $this->createMock(EntityRepositoryInterface::class), $this->createMock(LanguageManagerInterface::class));
+    $view = $this->createMock(ViewExecutable::class);
+    $display = $this->createMock(DisplayPluginBase::class);
+    $field->init($view, $display);
+    $this->assertEquals('', $field->render($row));
+  }
+
+}
diff --git a/core/modules/user/src/Plugin/views/field/Permissions.php b/core/modules/user/src/Plugin/views/field/Permissions.php
index 705ba7a589..ff77b3102d 100644
--- a/core/modules/user/src/Plugin/views/field/Permissions.php
+++ b/core/modules/user/src/Plugin/views/field/Permissions.php
@@ -87,7 +87,10 @@ public function preRender(&$values) {
 
     $rids = [];
     foreach ($values as $result) {
-      $user_rids = $this->getEntity($result)->getRoles();
+      if (!$user = $this->getEntity($result)) {
+        continue;
+      }
+      $user_rids = $user->getRoles();
       $uid = $this->getValue($result);
 
       foreach ($user_rids as $rid) {
diff --git a/core/modules/user/tests/src/Unit/Plugin/views/field/PermissionsTest.php b/core/modules/user/tests/src/Unit/Plugin/views/field/PermissionsTest.php
new file mode 100644
index 0000000000..ed4a4ef906
--- /dev/null
+++ b/core/modules/user/tests/src/Unit/Plugin/views/field/PermissionsTest.php
@@ -0,0 +1,53 @@
+<?php
+
+namespace Drupal\Tests\user\Unit\Plugin\views\field;
+
+use Drupal\contact\Plugin\views\field\ContactLink;
+use Drupal\Core\Access\AccessManagerInterface;
+use Drupal\Core\Entity\EntityRepositoryInterface;
+use Drupal\Core\Entity\EntityTypeManagerInterface;
+use Drupal\Core\Extension\ModuleHandlerInterface;
+use Drupal\Core\Language\LanguageManagerInterface;
+use Drupal\Core\StringTranslation\TranslationInterface;
+use Drupal\Tests\UnitTestCase;
+use Drupal\user\PermissionHandlerInterface;
+use Drupal\user\Plugin\views\field\Permissions;
+use Drupal\views\Plugin\views\display\DisplayPluginBase;
+use Drupal\views\ResultRow;
+use Drupal\views\ViewExecutable;
+use Symfony\Component\DependencyInjection\ContainerBuilder;
+
+/**
+ * @coversDefaultClass \Drupal\user\Plugin\views\field\Permissions
+ * @group user
+ */
+class PermissionsTest extends UnitTestCase {
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function tearDown() {
+    parent::tearDown();
+    $container = new \Drupal\Core\DependencyInjection\ContainerBuilder();
+    \Drupal::setContainer($container);
+  }
+
+  /**
+   * Tests the preRender method.
+   *
+   * @covers ::preRender
+   */
+  public function testPreRender() {
+    $values = [new ResultRow()];
+    $container = new ContainerBuilder();
+    $container->set('string_translation', $this->createMock(TranslationInterface::class));
+    $container->set('user.permissions', $this->createMock(PermissionHandlerInterface::class));
+    \Drupal::setContainer($container);
+    $field = new Permissions([], '', [], $this->createMock(ModuleHandlerInterface::class), $this->createMock(EntityTypeManagerInterface::class));
+    $view = $this->createMock(ViewExecutable::class);
+    $display = $this->createMock(DisplayPluginBase::class);
+    $field->init($view, $display);
+    $this->assertEquals('', $field->preRender($values));
+  }
+
+}
diff --git a/core/modules/views/src/Plugin/views/field/BulkForm.php b/core/modules/views/src/Plugin/views/field/BulkForm.php
index 5ee5891d9d..beb5abc773 100644
--- a/core/modules/views/src/Plugin/views/field/BulkForm.php
+++ b/core/modules/views/src/Plugin/views/field/BulkForm.php
@@ -308,7 +308,11 @@ public function viewsForm(&$form, FormStateInterface $form_state) {
       // Render checkboxes for all rows.
       $form[$this->options['id']]['#tree'] = TRUE;
       foreach ($this->view->result as $row_index => $row) {
-        $entity = $this->getEntityTranslation($this->getEntity($row), $row);
+        if (!$entity = $this->getEntity($row)) {
+          $form[$this->options['id']][$row_index] = [];
+          continue;
+        }
+        $entity = $this->getEntityTranslation($entity, $row);
 
         $form[$this->options['id']][$row_index] = [
           '#type' => 'checkbox',
diff --git a/core/modules/views/src/Plugin/views/field/EntityLink.php b/core/modules/views/src/Plugin/views/field/EntityLink.php
index f7b2877a6c..2ae4d032e6 100644
--- a/core/modules/views/src/Plugin/views/field/EntityLink.php
+++ b/core/modules/views/src/Plugin/views/field/EntityLink.php
@@ -26,6 +26,9 @@ public function render(ResultRow $row) {
    */
   protected function renderLink(ResultRow $row) {
     if ($this->options['output_url_as_text']) {
+      if (!$urlInfo = $this->getUrlInfo($row)) {
+        return '';
+      }
       return $this->getUrlInfo($row)->toString();
     }
     return parent::renderLink($row);
@@ -37,6 +40,9 @@ protected function renderLink(ResultRow $row) {
   protected function getUrlInfo(ResultRow $row) {
     $template = $this->getEntityLinkTemplate();
     $entity = $this->getEntity($row);
+    if (!$entity) {
+      return NULL;
+    }
     if ($this->languageManager->isMultilingual()) {
       $entity = $this->getEntityTranslation($entity, $row);
     }
diff --git a/core/modules/views/src/Plugin/views/field/EntityOperations.php b/core/modules/views/src/Plugin/views/field/EntityOperations.php
index 32a30ad1ae..5d5c9abc58 100644
--- a/core/modules/views/src/Plugin/views/field/EntityOperations.php
+++ b/core/modules/views/src/Plugin/views/field/EntityOperations.php
@@ -139,7 +139,10 @@ public function buildOptionsForm(&$form, FormStateInterface $form_state) {
    * {@inheritdoc}
    */
   public function render(ResultRow $values) {
-    $entity = $this->getEntityTranslation($this->getEntity($values), $values);
+    if (!$entity = $this->getEntity($values)) {
+      return [];
+    }
+    $entity = $this->getEntityTranslation($entity, $values);
     $operations = $this->entityTypeManager->getListBuilder($entity->getEntityTypeId())->getOperations($entity);
     if ($this->options['destination']) {
       foreach ($operations as &$operation) {
diff --git a/core/modules/views/src/Plugin/views/field/LinkBase.php b/core/modules/views/src/Plugin/views/field/LinkBase.php
index 6534482f2d..bce83c2780 100644
--- a/core/modules/views/src/Plugin/views/field/LinkBase.php
+++ b/core/modules/views/src/Plugin/views/field/LinkBase.php
@@ -177,6 +177,9 @@ public function query() {
    */
   public function render(ResultRow $row) {
     $access = $this->checkUrlAccess($row);
+    if ($access === NULL) {
+      return '';
+    }
     $build = ['#markup' => $access->isAllowed() ? $this->renderLink($row) : ''];
     BubbleableMetadata::createFromObject($access)->applyTo($build);
     return $build;
@@ -188,12 +191,13 @@ public function render(ResultRow $row) {
    * @param \Drupal\views\ResultRow $row
    *   A view result row.
    *
-   * @return \Drupal\Core\Access\AccessResultInterface
+   * @return \Drupal\Core\Access\AccessResultInterface|null
    *   The access result.
    */
   protected function checkUrlAccess(ResultRow $row) {
-    $url = $this->getUrlInfo($row);
-    return $this->accessManager->checkNamedRoute($url->getRouteName(), $url->getRouteParameters(), $this->currentUser(), TRUE);
+    if ($url = $this->getUrlInfo($row)) {
+      return $this->accessManager->checkNamedRoute($url->getRouteName(), $url->getRouteParameters(), $this->currentUser(), TRUE);
+    }
   }
 
   /**
@@ -202,7 +206,7 @@ protected function checkUrlAccess(ResultRow $row) {
    * @param \Drupal\views\ResultRow $row
    *   A view result row.
    *
-   * @return \Drupal\Core\Url
+   * @return \Drupal\Core\Url|null
    *   The URI elements of the link.
    */
   abstract protected function getUrlInfo(ResultRow $row);
@@ -218,7 +222,9 @@ protected function checkUrlAccess(ResultRow $row) {
    */
   protected function renderLink(ResultRow $row) {
     $this->options['alter']['make_link'] = TRUE;
-    $this->options['alter']['url'] = $this->getUrlInfo($row);
+    if ($urlInfo = $this->getUrlInfo($row)) {
+      $this->options['alter']['url'] = $this->getUrlInfo($row);
+    }
     $text = !empty($this->options['text']) ? $this->sanitizeValue($this->options['text']) : $this->getDefaultLabel();
     $this->addLangcode($row);
     return $text;
@@ -231,8 +237,7 @@ protected function renderLink(ResultRow $row) {
    *   A view result row.
    */
   protected function addLangcode(ResultRow $row) {
-    $entity = $this->getEntity($row);
-    if ($this->languageManager->isMultilingual()) {
+    if (($entity = $this->getEntity($row)) && $this->languageManager->isMultilingual()) {
       $this->options['alter']['language'] = $this->getEntityTranslation($entity, $row)->language();
     }
   }
diff --git a/core/modules/views/src/Plugin/views/field/RenderedEntity.php b/core/modules/views/src/Plugin/views/field/RenderedEntity.php
index f70b03f5d9..9cfd16ae96 100644
--- a/core/modules/views/src/Plugin/views/field/RenderedEntity.php
+++ b/core/modules/views/src/Plugin/views/field/RenderedEntity.php
@@ -146,15 +146,16 @@ public function buildOptionsForm(&$form, FormStateInterface $form_state) {
    * {@inheritdoc}
    */
   public function render(ResultRow $values) {
-    $entity = $this->getEntityTranslation($this->getEntity($values), $values);
+    if (!$entity = $this->getEntity($values)) {
+      return '';
+    }
+    $entity = $this->getEntityTranslation($entity, $values);
     $build = [];
-    if (isset($entity)) {
-      $access = $entity->access('view', NULL, TRUE);
-      $build['#access'] = $access;
-      if ($access->isAllowed()) {
-        $view_builder = $this->entityTypeManager->getViewBuilder($this->getEntityTypeId());
-        $build += $view_builder->view($entity, $this->options['view_mode']);
-      }
+    $access = $entity->access('view', NULL, TRUE);
+    $build['#access'] = $access;
+    if ($access->isAllowed()) {
+      $view_builder = $this->entityTypeManager->getViewBuilder($this->getEntityTypeId());
+      $build += $view_builder->view($entity, $this->options['view_mode']);
     }
     return $build;
   }
diff --git a/core/modules/views/tests/src/Unit/Plugin/views/field/BulkFormTest.php b/core/modules/views/tests/src/Unit/Plugin/views/field/BulkFormTest.php
new file mode 100644
index 0000000000..857de5c735
--- /dev/null
+++ b/core/modules/views/tests/src/Unit/Plugin/views/field/BulkFormTest.php
@@ -0,0 +1,76 @@
+<?php
+
+namespace Drupal\Tests\views\Unit\Plugin\views\field;
+
+use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\StringTranslation\TranslationInterface;
+use Drupal\Tests\UnitTestCase;
+use Drupal\views\Plugin\views\field\BulkForm;
+use Drupal\views\Plugin\views\query\QueryPluginBase;
+use Drupal\views\ResultRow;
+use Drupal\views\ViewExecutable;
+use Symfony\Component\DependencyInjection\ContainerBuilder;
+
+/**
+ * @coversDefaultClass \Drupal\views\Plugin\views\field\BulkForm
+ * @group Views
+ */
+class BulkFormTest extends UnitTestCase {
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function tearDown() {
+    parent::tearDown();
+    $container = new \Drupal\Core\DependencyInjection\ContainerBuilder();
+    \Drupal::setContainer($container);
+  }
+
+  /**
+   * Tests the viewsForm method.
+   *
+   * @covers ::viewsForm
+   */
+  public function testViewsForm() {
+    $row = new ResultRow();
+
+    $container = new ContainerBuilder();
+    $container->set('string_translation', $this->createMock(TranslationInterface::class));
+    \Drupal::setContainer($container);
+
+    $field = $this->getMockBuilder(BulkForm::class)
+      ->setMethods(['getEntityType', 'getEntity'])
+      ->disableOriginalConstructor()
+      ->getMock();
+    $field->expects($this->any())
+      ->method('getEntityType')
+      ->willReturn('foo');
+    $field->expects($this->any())
+      ->method('getEntity')
+      ->willReturn(NULL);
+
+    $query = $this->getMockBuilder(QueryPluginBase::class)
+      ->setMethods(['getEntityTableInfo'])
+      ->disableOriginalConstructor()
+      ->getMock();
+    $query->expects($this->any())
+      ->method('getEntityTableInfo')
+      ->willReturn([]);
+    $view = $this->getMockBuilder(ViewExecutable::class)
+      ->setMethods(['getQuery'])
+      ->disableOriginalConstructor()
+      ->getMock();
+    $view->expects($this->any())
+      ->method('getQuery')
+      ->willReturn($query);
+    $view->result = [$row];
+    $view->query = $query;
+    $field->view = $view;
+    $field->options = ['id' => 'bar', 'action_title' => 'zee'];
+    $form_state = $this->createMock(FormStateInterface::class);
+    $form = [];
+    $field->viewsForm($form, $form_state);
+    $this->assertNotEmpty($form, print_r($field->view->result, 1));
+  }
+
+}
diff --git a/core/modules/views/tests/src/Unit/Plugin/views/field/LinkBaseTest.php b/core/modules/views/tests/src/Unit/Plugin/views/field/LinkBaseTest.php
new file mode 100644
index 0000000000..e64cc3abbd
--- /dev/null
+++ b/core/modules/views/tests/src/Unit/Plugin/views/field/LinkBaseTest.php
@@ -0,0 +1,62 @@
+<?php
+
+namespace Drupal\Tests\views\Unit\Plugin\views\field;
+
+use Drupal\Core\Access\AccessManagerInterface;
+use Drupal\Core\Access\AccessResultAllowed;
+use Drupal\Core\Entity\EntityRepositoryInterface;
+use Drupal\Core\Entity\EntityTypeManagerInterface;
+use Drupal\Core\Language\LanguageManagerInterface;
+use Drupal\Core\StringTranslation\TranslationInterface;
+use Drupal\Tests\UnitTestCase;
+use Drupal\views\Plugin\views\display\DisplayPluginBase;
+use Drupal\views\Plugin\views\field\LinkBase;
+use Drupal\views\ResultRow;
+use Drupal\views\ViewExecutable;
+use Symfony\Component\DependencyInjection\ContainerBuilder;
+
+/**
+ * @coversDefaultClass \Drupal\views\Plugin\views\field\EntityLink
+ * @group Views
+ */
+class LinkBaseTest extends UnitTestCase {
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function tearDown() {
+    parent::tearDown();
+    $container = new \Drupal\Core\DependencyInjection\ContainerBuilder();
+    \Drupal::setContainer($container);
+  }
+
+  /**
+   * @covers ::render
+   */
+  public function testRender() {
+    $row = new ResultRow();
+    $container = new ContainerBuilder();
+    $container->set('string_translation', $this->createMock(TranslationInterface::class));
+    \Drupal::setContainer($container);
+
+    $access = new AccessResultAllowed();
+    $languageManager = $this->createMock(LanguageManagerInterface::class);
+    $languageManager->expects($this->any())
+      ->method('isMultilingual')
+      ->willReturn(TRUE);
+    $field = $this->getMockBuilder(LinkBase::class)
+      ->setConstructorArgs([[], 'foo', [], $this->createMock(AccessManagerInterface::class), $this->createMock(EntityTypeManagerInterface::class), $this->createMock(EntityRepositoryInterface::class), $languageManager])
+      ->setMethods(['checkUrlAccess', 'getUrlInfo'])
+      ->getMock();
+    $field->expects($this->any())
+      ->method('checkUrlAccess')
+      ->willReturn($access);
+
+    $view = $this->createMock(ViewExecutable::class);
+    $display = $this->createMock(DisplayPluginBase::class);
+
+    $field->init($view, $display);
+    $this->assertEquals('', $field->render($row));
+  }
+
+}
diff --git a/core/modules/views/tests/src/Unit/Plugin/views/field/RenderedEntityTest.php b/core/modules/views/tests/src/Unit/Plugin/views/field/RenderedEntityTest.php
new file mode 100644
index 0000000000..403d6c7d46
--- /dev/null
+++ b/core/modules/views/tests/src/Unit/Plugin/views/field/RenderedEntityTest.php
@@ -0,0 +1,41 @@
+<?php
+
+namespace Drupal\Tests\views\Unit\Plugin\views\field;
+
+use Drupal\Core\Access\AccessManagerInterface;
+use Drupal\Core\Access\AccessResultAllowed;
+use Drupal\Core\Access\AccessResultInterface;
+use Drupal\Core\Entity\EntityDisplayRepositoryInterface;
+use Drupal\Core\Entity\EntityRepositoryInterface;
+use Drupal\Core\Entity\EntityTypeManagerInterface;
+use Drupal\Core\Language\Language;
+use Drupal\Core\Language\LanguageManagerInterface;
+use Drupal\Core\StringTranslation\TranslationInterface;
+use Drupal\Tests\UnitTestCase;
+use Drupal\views\Plugin\views\display\DisplayPluginBase;
+use Drupal\views\Plugin\views\field\EntityLink;
+use Drupal\views\Plugin\views\field\LinkBase;
+use Drupal\views\Plugin\views\field\RenderedEntity;
+use Drupal\views\ResultRow;
+use Drupal\views\ViewExecutable;
+use Symfony\Component\DependencyInjection\ContainerBuilder;
+
+/**
+ * @coversDefaultClass \Drupal\views\Plugin\views\field\RenderedEntity
+ * @group Views
+ */
+class RenderedEntityTest extends UnitTestCase {
+
+  /**
+   * @covers ::render
+   */
+  public function testRender() {
+    $row = new ResultRow();
+    $field = new RenderedEntity([], '', [], $this->createMock(EntityTypeManagerInterface::class), $this->createMock(LanguageManagerInterface::class), $this->createMock(EntityRepositoryInterface::class), $this->createMock(EntityDisplayRepositoryInterface::class));
+    $view = $this->createMock(ViewExecutable::class);
+    $display = $this->createMock(DisplayPluginBase::class);
+    $field->init($view, $display);
+    $this->assertEquals('', $field->render($row));
+  }
+
+}
