diff --git a/core/modules/edit/edit.routing.yml b/core/modules/edit/edit.routing.yml
index b709d0a..adef7f1 100644
--- a/core/modules/edit/edit.routing.yml
+++ b/core/modules/edit/edit.routing.yml
@@ -16,15 +16,18 @@ edit_field_form:
   pattern: '/edit/form/{entity_type}/{entity}/{field_name}/{langcode}/{view_mode_id}'
   defaults:
     _controller: '\Drupal\edit\EditController::fieldForm'
+  options:
+    _access_mode: 'ALL'
   requirements:
     _permission: 'access in-place editing'
     _access_edit_entity_field: 'TRUE'
 
-
 edit_entity_save:
   pattern: '/edit/entity/{entity_type}/{entity}'
   defaults:
     _controller: '\Drupal\edit\EditController::entitySave'
+  options:
+    _access_mode: 'ALL'
   requirements:
     _permission: 'access in-place editing'
     _access_edit_entity: 'TRUE'
diff --git a/core/modules/edit/edit.services.yml b/core/modules/edit/edit.services.yml
index 646878e..4202963 100644
--- a/core/modules/edit/edit.services.yml
+++ b/core/modules/edit/edit.services.yml
@@ -4,6 +4,7 @@ services:
     arguments: ['@container.namespaces']
   access_check.edit.entity_field:
     class: Drupal\edit\Access\EditEntityFieldAccessCheck
+    arguments: ['@plugin.manager.entity', '@field.info']
     tags:
       - { name: access_check }
   access_check.edit.entity:
diff --git a/core/modules/edit/lib/Drupal/edit/Access/EditEntityFieldAccessCheck.php b/core/modules/edit/lib/Drupal/edit/Access/EditEntityFieldAccessCheck.php
index 9559be7..094f1dd 100644
--- a/core/modules/edit/lib/Drupal/edit/Access/EditEntityFieldAccessCheck.php
+++ b/core/modules/edit/lib/Drupal/edit/Access/EditEntityFieldAccessCheck.php
@@ -13,6 +13,8 @@
 use Symfony\Component\HttpFoundation\Request;
 use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
 use Drupal\Core\Entity\EntityInterface;
+use Drupal\field\FieldInfo;
+use Drupal\Core\Entity\EntityManager;
 
 /**
  * Access check for editing entity fields.
@@ -20,6 +22,33 @@
 class EditEntityFieldAccessCheck implements StaticAccessCheckInterface, EditEntityFieldAccessCheckInterface {
 
   /**
+   * The entity manager.
+   *
+   * @var \Drupal\Core\Entity\EntityManager
+   */
+  protected $entityManager;
+
+  /**
+   * The field info.
+   *
+   * @var \Drupal\field\FieldInfo
+   */
+  protected $fieldInfo;
+
+  /**
+   * Constructs a EditEntityFieldAccessCheck object.
+   *
+   * @param \Drupal\Core\Entity\EntityManager $entity_manager
+   *   The entity manager.
+   * @param \Drupal\field\FieldInfo $field_info
+   *   The field info.
+   */
+  public function __construct(EntityManager $entity_manager, FieldInfo $field_info) {
+    $this->entityManager = $entity_manager;
+    $this->fieldInfo = $field_info;
+  }
+
+  /**
    * {@inheritdoc}
    */
   public function appliesTo() {
@@ -42,7 +71,7 @@ public function access(Route $route, Request $request) {
    * {@inheritdoc}
    */
   public function accessEditEntityField(EntityInterface $entity, $field_name) {
-    return $entity->access('update') && ($field = field_info_field($field_name)) && field_access('edit', $field, $entity->entityType(), $entity);
+    return $entity->access('update') && ($field = $this->fieldInfo->getField($field_name)) && field_access('edit', $field, $entity->entityType(), $entity);
   }
 
   /**
@@ -53,10 +82,10 @@ protected function validateAndUpcastRequestAttributes(Request $request) {
     if (!is_object($entity = $request->attributes->get('entity'))) {
       $entity_id = $entity;
       $entity_type = $request->attributes->get('entity_type');
-      if (!$entity_type || !entity_get_info($entity_type)) {
+      if (!$entity_type || !$this->entityManager->getDefinition($entity_type)) {
         throw new NotFoundHttpException();
       }
-      $entity = entity_load($entity_type, $entity_id);
+      $entity = $this->entityManager->getStorageController($entity_type)->load($entity_id);
       if (!$entity) {
         throw new NotFoundHttpException();
       }
@@ -65,7 +94,7 @@ protected function validateAndUpcastRequestAttributes(Request $request) {
 
     // Validate the field name and language.
     $field_name = $request->attributes->get('field_name');
-    if (!$field_name || !field_info_instance($entity->entityType(), $field_name, $entity->bundle())) {
+    if (!$field_name || !$this->fieldInfo->getInstance($entity->entityType(), $field_name, $entity->bundle())) {
       throw new NotFoundHttpException();
     }
     $langcode = $request->attributes->get('langcode');
diff --git a/core/modules/edit/lib/Drupal/edit/Tests/EditLoadingTest.php b/core/modules/edit/lib/Drupal/edit/Tests/EditLoadingTest.php
index e7e2571..7b01ade 100644
--- a/core/modules/edit/lib/Drupal/edit/Tests/EditLoadingTest.php
+++ b/core/modules/edit/lib/Drupal/edit/Tests/EditLoadingTest.php
@@ -89,6 +89,34 @@ function testUserWithoutPermission() {
     $response = $this->retrieveMetadata(array('node/1/body/und/full'));
     $this->assertIdentical('{}', $response);
     $this->assertResponse(403);
+
+    // Edit's JavaScript would never hit these endpoints if the metadata was
+    // empty as above, but we need to make sure that malicious users aren't able
+    // to use any of the other endpoints either.
+    $response = $this->retrieveAttachments(array('form'));
+    // @todo Uncomment the below once https://drupal.org/node/2063303 is fixed.
+    // $this->assertIdentical('[]', $response);
+    $this->assertResponse(403);
+    $response = $this->retrieveFieldForm('node/1/body/und/full');
+    // @todo Uncomment the below once https://drupal.org/node/2063303 is fixed.
+    // $this->assertIdentical('[]', $response);
+    $this->assertResponse(403);
+    $edit = array();
+    $edit['form_id'] = 'edit_field_form';
+    $edit['form_token'] = 'xIOzMjuc-PULKsRn_KxFn7xzNk5Bx7XKXLfQfw1qOnA';
+    $edit['form_build_id'] = 'form-kVmovBpyX-SJfTT5kY0pjTV35TV-znor--a64dEnMR8';
+    $edit['body[und][0][summary]'] = '';
+    $edit['body[und][0][value]'] = '<p>Malicious content.</p>';
+    $edit['body[und][0][format]'] = 'filtered_html';
+    $edit['op'] = t('Save');
+    $response = $this->submitFieldForm('node/1/body/und/full', $edit);
+    // @todo Uncomment the below once https://drupal.org/node/2063303 is fixed.
+    // $this->assertIdentical('[]', $response);
+    $this->assertResponse(403);
+    $response = $this->saveEntity('node/1');
+    // @todo Uncomment the below once https://drupal.org/node/2063303 is fixed.
+    // $this->assertIdentical('[]', $response);
+    $this->assertResponse(403);
   }
 
   /**
diff --git a/core/modules/edit/lib/Drupal/edit/Tests/edit/Access/EditEntityAccessCheckTest.php b/core/modules/edit/lib/Drupal/edit/Tests/edit/Access/EditEntityAccessCheckTest.php
new file mode 100644
index 0000000..e2a3b41
--- /dev/null
+++ b/core/modules/edit/lib/Drupal/edit/Tests/edit/Access/EditEntityAccessCheckTest.php
@@ -0,0 +1,72 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\edit\Tests\edit\Access\EditEntityAccessCheckTest.
+ */
+
+namespace Drupal\edit\Tests\edit\Access;
+
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\Routing\Route;
+use Drupal\Core\Access\AccessCheckInterface;
+use Drupal\edit\Access\EditEntityAccessCheck;
+use Drupal\Tests\UnitTestCase;
+
+/**
+ * Tests the edit entity access controller.
+ *
+ * @group Drupal
+ * @group Edit
+ *
+ * @see \Drupal\edit\Access\EditEntityAccessCheck
+ */
+class EditEntityAccessCheckTest extends UnitTestCase {
+
+  public static function getInfo() {
+    return array(
+      'name' => 'Edit entity access check test',
+      'description' => 'Unit test of edit entity access check.',
+      'group' => 'Edit'
+    );
+  }
+
+  /**
+   * Tests the appliesTo method for the access checker.
+   */
+  public function testAppliesTo() {
+    $entity_access = new EditEntityAccessCheck();
+    $this->assertEquals($entity_access->appliesTo(), array('_access_edit_entity'), 'Access checker returned the expected appliesTo() array.');
+  }
+
+  /**
+   * Tests the method for checking access to routes.
+   */
+  public function testAccess() {
+    $route = new Route('/edit/entity/node/1', array(), array('_access_edit_entity' => 'TRUE'));
+    $request = new Request();
+
+    $editable_node = $this->getMockBuilder('Drupal\node\Entity\Node')
+      ->disableOriginalConstructor()
+      ->getMock();
+    $editable_node->expects($this->any())
+      ->method('access')
+      ->will($this->returnValue(TRUE));
+    $access_check = new EditEntityAccessCheck();
+    $request->attributes->set('entity', $editable_node);
+    $access = $access_check->access($route, $request);
+    $this->assertSame(AccessCheckInterface::ALLOW, $access);
+
+    $readonly_node = $this->getMockBuilder('Drupal\node\Entity\Node')
+      ->disableOriginalConstructor()
+      ->getMock();
+    $readonly_node->expects($this->any())
+      ->method('access')
+      ->will($this->returnValue(FALSE));
+    $access_check = new EditEntityAccessCheck();
+    $request->attributes->set('entity', $readonly_node);
+    $access = $access_check->access($route, $request);
+    $this->assertSame(AccessCheckInterface::DENY, $access);
+  }
+
+}
diff --git a/core/modules/edit/lib/Drupal/edit/Tests/edit/Access/EditEntityFieldAccessCheckTest.php b/core/modules/edit/lib/Drupal/edit/Tests/edit/Access/EditEntityFieldAccessCheckTest.php
new file mode 100644
index 0000000..7240854
--- /dev/null
+++ b/core/modules/edit/lib/Drupal/edit/Tests/edit/Access/EditEntityFieldAccessCheckTest.php
@@ -0,0 +1,342 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\edit\Tests\edit\Access\EditEntityFieldAccessCheckTest.
+ */
+
+namespace Drupal\edit\Tests\edit\Access {
+
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\Routing\Route;
+use Drupal\Core\Access\AccessCheckInterface;
+use Drupal\edit\Access\EditEntityFieldAccessCheck;
+use Drupal\Tests\UnitTestCase;
+use Drupal\field\FieldInterface;
+use Drupal\Core\Language\Language;
+use Drupal\Core\Entity\EntityInterface;
+
+/**
+ * Tests the edit entity field access controller.
+ *
+ * @group Drupal
+ * @group Edit
+ *
+ * @see \Drupal\edit\Access\EditEntityFieldAccessCheck
+ */
+class EditEntityFieldAccessCheckTest extends UnitTestCase {
+
+  /**
+   * The tested access checker.
+   *
+   * @var \Drupal\edit\Access\EditEntityFieldAccessCheck
+   */
+  protected $editAccessCheck;
+
+  /**
+   * The mocked entity manager.
+   *
+   * @var \Drupal\Core\Entity\EntityManager|\PHPUnit_Framework_MockObject_MockObject
+   */
+  protected $entityManager;
+
+  /**
+   * The mocked field info.
+   *
+   * @var \Drupal\field\FieldInfo|\PHPUnit_Framework_MockObject_MockObject
+   */
+  protected $fieldInfo;
+
+  /**
+   * The mocked entity storage controller.
+   *
+   * @var \Drupal\Core\Entity\EntityStorageControllerInterface|\PHPUnit_Framework_MockObject_MockObject
+   */
+  protected $entityStorageController;
+
+  public static function getInfo() {
+    return array(
+      'name' => 'Edit entity field access check test',
+      'description' => 'Unit test of edit entity field access check.',
+      'group' => 'Edit'
+    );
+  }
+
+  protected function setUp() {
+    $this->entityManager = $this->getMockBuilder('Drupal\Core\Entity\EntityManager')
+      ->disableOriginalConstructor()
+      ->getMock();
+
+    $this->entityStorageController = $this->getMock('Drupal\Core\Entity\EntityStorageControllerInterface');
+
+    $this->entityManager->expects($this->any())
+      ->method('getStorageController')
+      ->will($this->returnValue($this->entityStorageController));
+
+    $this->fieldInfo = $this->getMockBuilder('Drupal\field\FieldInfo')
+      ->disableOriginalConstructor()
+      ->getMock();
+
+    $this->editAccessCheck = new EditEntityFieldAccessCheck($this->entityManager, $this->fieldInfo);
+  }
+
+  /**
+   * Tests the appliesTo method for the access checker.
+   */
+  public function testAppliesTo() {
+    $this->assertEquals($this->editAccessCheck->appliesTo(), array('_access_edit_entity_field'), 'Access checker returned the expected appliesTo() array.');
+  }
+
+  /**
+   * Provides test data for testAccess()
+   *
+   * @see \Drupal\edit\Tests\edit\Access\EditEntityFieldAccessCheckTest::testAccess()
+   */
+  public function providerTestAccess() {
+    $editable_entity = $this->getMockBuilder('Drupal\entity_test\Entity\EntityTest')
+      ->disableOriginalConstructor()
+      ->getMock();
+    $editable_entity->expects($this->any())
+      ->method('access')
+      ->will($this->returnValue(TRUE));
+
+    $non_editable_entity = $this->getMockBuilder('Drupal\entity_test\Entity\EntityTest')
+      ->disableOriginalConstructor()
+      ->getMock();
+    $non_editable_entity->expects($this->any())
+      ->method('access')
+      ->will($this->returnValue(FALSE));
+
+    $empty_field = NULL;
+    $field_with_access = $this->getMockBuilder('Drupal\field\Entity\Field')
+      ->disableOriginalConstructor()
+      ->getMock();
+    $field_with_access->expects($this->any())
+      ->method('access')
+      ->will($this->returnValue(TRUE));
+    $field_without_access = $this->getMockBuilder('Drupal\field\Entity\Field')
+      ->disableOriginalConstructor()
+      ->getMock();
+    $field_without_access->expects($this->any())
+      ->method('access')
+      ->will($this->returnValue(FALSE));
+
+    $data = array();
+    $data[] = array($editable_entity, $field_with_access, AccessCheckInterface::ALLOW);
+    $data[] = array($non_editable_entity, $field_with_access, AccessCheckInterface::DENY);
+    $data[] = array($editable_entity, $field_without_access, AccessCheckInterface::DENY);
+    $data[] = array($editable_entity, $empty_field, AccessCheckInterface::DENY);
+
+    return $data;
+  }
+
+  /**
+   * Tests the method for checking access to routes.
+   *
+   * @param \Drupal\Core\Entity\EntityInterface $entity
+   *   A mocked entity.
+   * @param \Drupal\field\FieldInterface $field
+   *   A mocked field.
+   * @param bool|null $expected_result
+   *   The expected result of the access call.
+   *
+   * @dataProvider providerTestAccess
+   */
+  public function testAccess(EntityInterface $entity, FieldInterface $field = NULL, $expected_result = AccessCheckInterface::ALLOW) {
+    $route = new Route('/edit/form/node/1/body/und/full', array(), array('_access_edit_entity_field' => 'TRUE'));
+    $request = new Request();
+
+    $this->fieldInfo->expects($this->any())
+      ->method('getField')
+      ->will($this->returnValue($field));
+
+    // Prepare the request to be valid.
+    $request->attributes->set('entity', $entity);
+    $request->attributes->set('entity_test', 'test_entity');
+    $request->attributes->set('field_name', 'example');
+    $request->attributes->set('langcode', Language::LANGCODE_NOT_SPECIFIED);
+
+    $this->fieldInfo->expects($this->any())
+      ->method('getInstance')
+      ->will($this->returnValue(array(
+        'example' => array(
+          'field_name' => 'example',
+        )
+      )));
+
+    $access = $this->editAccessCheck->access($route, $request);
+    $this->assertSame($expected_result, $access);
+  }
+
+  /**
+   * Tests the access method with an undefined entity type.
+   *
+   * @expectedException \Symfony\Component\HttpKernel\Exception\NotFoundHttpException
+   */
+  public function testAccessWithUndefinedEntityType() {
+    $route = new Route('/edit/form/node/1/body/und/full', array(), array('_access_edit_entity_field' => 'TRUE'));
+    $request = new Request();
+    $request->attributes->set('entity_type', 'non_valid');
+
+    $this->entityManager->expects($this->once())
+      ->method('getDefinition')
+      ->with('non_valid')
+      ->will($this->returnValue(NULL));
+
+    $this->editAccessCheck->access($route, $request);
+  }
+
+  /**
+   * Tests the access method with a non existing entity.
+   *
+   * @expectedException \Symfony\Component\HttpKernel\Exception\NotFoundHttpException
+   */
+  public function testAccessWithNotExistingEntity() {
+    $route = new Route('/edit/form/node/1/body/und/full', array(), array('_access_edit_entity_field' => 'TRUE'));
+    $request = new Request();
+    $request->attributes->set('entity_type', 'entity_test');
+    $request->attributes->set('entity', 1);
+
+    $this->entityManager->expects($this->once())
+      ->method('getDefinition')
+      ->with('entity_test')
+      ->will($this->returnValue(array('id' => 'entity_test')));
+
+    $this->entityStorageController->expects($this->once())
+      ->method('load')
+      ->with(1)
+      ->will($this->returnValue(NULL));
+
+    $this->editAccessCheck->access($route, $request);
+  }
+
+  /**
+   * Tests the access method with a forgotten passed field_name
+   *
+   * @expectedException \Symfony\Component\HttpKernel\Exception\NotFoundHttpException
+   */
+  public function testAccessWithNotPassedFieldName() {
+    $route = new Route('/edit/form/node/1/body/und/full', array(), array('_access_edit_entity_field' => 'TRUE'));
+    $request = new Request();
+    $request->attributes->set('entity_type', 'entity_test');
+
+    $entity = $this->getMockBuilder('Drupal\entity_test\Entity\EntityTest')
+      ->disableOriginalConstructor()
+      ->getMock();
+
+    $request->attributes->set('entity', $entity);
+
+    $this->editAccessCheck->access($route, $request);
+  }
+
+  /**
+   * Tests the access method with a non existing field.
+   *
+   * @expectedException \Symfony\Component\HttpKernel\Exception\NotFoundHttpException
+   */
+  public function testAccessWithNonExistingField() {
+    $route = new Route('/edit/form/node/1/body/und/full', array(), array('_access_edit_entity_field' => 'TRUE'));
+    $request = new Request();
+    $request->attributes->set('entity_type', 'entity_test');
+
+    $entity = $this->getMockBuilder('Drupal\entity_test\Entity\EntityTest')
+      ->disableOriginalConstructor()
+      ->getMock();
+    $entity->expects($this->any())
+      ->method('entityType')
+      ->will($this->returnValue('entity_test'));
+    $entity->expects($this->any())
+      ->method('bundle')
+      ->will($this->returnValue('test_bundle'));
+
+    $request->attributes->set('entity', $entity);
+    $request->attributes->set('field_name', 'not_valid');
+
+    $this->fieldInfo->expects($this->once())
+      ->method('getInstance')
+      ->with('entity_test', 'not_valid', 'test_bundle')
+      ->will($this->returnValue(NULL));
+
+    $this->editAccessCheck->access($route, $request);
+  }
+
+  /**
+   * Tests the access method with a forgotten passed language.
+   *
+   * @expectedException \Symfony\Component\HttpKernel\Exception\NotFoundHttpException
+   */
+  public function testAccessWithNotPassedLanguage() {
+    $route = new Route('/edit/form/node/1/body/und/full', array(), array('_access_edit_entity_field' => 'TRUE'));
+    $request = new Request();
+    $request->attributes->set('entity_type', 'entity_test');
+
+    $entity = $this->getMockBuilder('Drupal\entity_test\Entity\EntityTest')
+      ->disableOriginalConstructor()
+      ->getMock();
+    $request->attributes->set('entity', $entity);
+
+    $request->attributes->set('field_name', 'valid');
+
+    $field = $this->getMockBuilder('Drupal\field\Entity\Field')
+      ->disableOriginalConstructor()
+      ->getMock();
+
+    $this->fieldInfo->expects($this->once())
+      ->method('getInstance')
+      ->will($this->returnValue($field));
+
+    $this->editAccessCheck->access($route, $request);
+  }
+
+  /**
+   * Tests the access method with an invalid language.
+   *
+   * @expectedException \Symfony\Component\HttpKernel\Exception\NotFoundHttpException
+   */
+  public function testAccessWithInvalidLanguage() {
+    $route = new Route('/edit/form/node/1/body/und/full', array(), array('_access_edit_entity_field' => 'TRUE'));
+    $request = new Request();
+    $request->attributes->set('entity_type', 'entity_test');
+
+    $entity = $this->getMockBuilder('Drupal\entity_test\Entity\EntityTest')
+      ->disableOriginalConstructor()
+      ->getMock();
+    $request->attributes->set('entity', $entity);
+
+    $request->attributes->set('field_name', 'valid');
+    $request->attributes->set('langcode', 'xx-lolspeak');
+
+    $field = $this->getMockBuilder('Drupal\field\Entity\Field')
+      ->disableOriginalConstructor()
+      ->getMock();
+
+    $this->fieldInfo->expects($this->once())
+      ->method('getInstance')
+      ->will($this->returnValue($field));
+
+    $this->editAccessCheck->access($route, $request);
+  }
+
+}
+
+}
+
+// @todo remove once field_access() and field_valid_language() can be injected.
+namespace {
+
+  use Drupal\Core\Language\Language;
+  use Drupal\field\FieldInterface;
+
+  if (!function_exists('field_access')) {
+    function field_access($op, FieldInterface $field, $entity_type, $entity = NULL, $account = NULL) {
+      return $field->access();
+    }
+  }
+
+  if (!function_exists('field_access')) {
+    function field_valid_language($langcode, $default = TRUE) {
+      return $langcode == Language::LANGCODE_NOT_SPECIFIED ? Language::LANGCODE_NOT_SPECIFIED : 'en';
+    }
+  }
+
+}
