diff --git a/core/modules/link/lib/Drupal/link/Plugin/Field/FieldFormatter/LinkFormatter.php b/core/modules/link/lib/Drupal/link/Plugin/Field/FieldFormatter/LinkFormatter.php
index 37df049..bd67402 100644
--- a/core/modules/link/lib/Drupal/link/Plugin/Field/FieldFormatter/LinkFormatter.php
+++ b/core/modules/link/lib/Drupal/link/Plugin/Field/FieldFormatter/LinkFormatter.php
@@ -147,6 +147,12 @@ public function viewElements(FieldItemListInterface $items) {
         $element[$delta] = array(
           '#markup' => String::checkPlain($link_title),
         );
+
+        if (!empty($item->_attributes)) {
+          // Take the fallback behavior of ___ by just setting the
+          // _attributes directly.
+          $item->_attributes += array('content' => $item->url);
+        }
       }
       else {
         $element[$delta] = array(
@@ -154,6 +160,7 @@ public function viewElements(FieldItemListInterface $items) {
           '#title' => $link_title,
           '#options' => $url->getOptions(),
         );
+
         if ($url->isExternal()) {
           $element[$delta]['#href'] = $url->getPath();
         }
@@ -161,6 +168,14 @@ public function viewElements(FieldItemListInterface $items) {
           $element[$delta]['#route_name'] = $url->getRouteName();
           $element[$delta]['#route_parameters'] = $url->getRouteParameters();
         }
+
+        if (!empty($item->_attributes)) {
+          $element[$delta]['#options'] += array ('attributes' => array());
+          $element[$delta]['#options']['attributes'] += $item->_attributes;
+          // Unset field item attributes since they have been included in the
+          // formatter output and should not be rendered in the field template.
+          unset($item->_attributes);
+        }
       }
     }
 
diff --git a/core/modules/link/lib/Drupal/link/Plugin/Field/FieldFormatter/LinkSeparateFormatter.php b/core/modules/link/lib/Drupal/link/Plugin/Field/FieldFormatter/LinkSeparateFormatter.php
index 7a427e5..a90d8b4 100644
--- a/core/modules/link/lib/Drupal/link/Plugin/Field/FieldFormatter/LinkSeparateFormatter.php
+++ b/core/modules/link/lib/Drupal/link/Plugin/Field/FieldFormatter/LinkSeparateFormatter.php
@@ -77,6 +77,14 @@ public function viewElements(FieldItemListInterface $items) {
         '#url_title' => $url_title,
         '#url' => $url,
       );
+
+      if (!empty($item->_attributes)) {
+        $element[$delta]['#options'] += array('attributes' => array());
+        $element[$delta]['#options']['attributes'] += $item->_attributes;
+        // Unset field item attributes since they have been included in the
+        // formatter output and should not be rendered in the field template.
+        unset($item->_attributes);
+      }
     }
     return $element;
   }
diff --git a/core/modules/rdf/lib/Drupal/rdf/Tests/Field/DateTimeFieldRdfaTest.php b/core/modules/rdf/lib/Drupal/rdf/Tests/Field/DateTimeFieldRdfaTest.php
index d859f25..2c7b3b2 100644
--- a/core/modules/rdf/lib/Drupal/rdf/Tests/Field/DateTimeFieldRdfaTest.php
+++ b/core/modules/rdf/lib/Drupal/rdf/Tests/Field/DateTimeFieldRdfaTest.php
@@ -58,6 +58,6 @@ public function setUp() {
    * Tests the default formatter.
    */
   public function testDefaultFormatter() {
-    $this->assertFormatterRdfa('datetime_default', 'http://schema.org/dateCreated', $this->testValue . 'Z', 'literal', 'http://www.w3.org/2001/XMLSchema#dateTime');
+    $this->assertFormatterRdfa(array('type'=>'datetime_default'), 'http://schema.org/dateCreated', array('value' => $this->testValue . 'Z', 'type' => 'literal', 'datatype' => 'http://www.w3.org/2001/XMLSchema#dateTime'));
   }
 }
diff --git a/core/modules/rdf/lib/Drupal/rdf/Tests/Field/EmailFieldRdfaTest.php b/core/modules/rdf/lib/Drupal/rdf/Tests/Field/EmailFieldRdfaTest.php
index 4a3550d..726d661 100644
--- a/core/modules/rdf/lib/Drupal/rdf/Tests/Field/EmailFieldRdfaTest.php
+++ b/core/modules/rdf/lib/Drupal/rdf/Tests/Field/EmailFieldRdfaTest.php
@@ -53,8 +53,9 @@ public function setUp() {
    */
   public function testAllFormatters() {
     // Test the plain formatter.
-    $this->assertFormatterRdfa('string', 'http://schema.org/email', $this->testValue);
+    $this->assertFormatterRdfa(array('type' => 'string'), 'http://schema.org/email', array('value' => $this->testValue));
+
     // Test the mailto formatter.
-    $this->assertFormatterRdfa('email_mailto', 'http://schema.org/email', $this->testValue);
+    $this->assertFormatterRdfa(array('type' => 'email_mailto'), 'http://schema.org/email', array('value' => $this->testValue));
   }
 }
diff --git a/core/modules/rdf/lib/Drupal/rdf/Tests/Field/FieldRdfaDatatypeCallbackTest.php b/core/modules/rdf/lib/Drupal/rdf/Tests/Field/FieldRdfaDatatypeCallbackTest.php
index 944082d..b6e6413 100644
--- a/core/modules/rdf/lib/Drupal/rdf/Tests/Field/FieldRdfaDatatypeCallbackTest.php
+++ b/core/modules/rdf/lib/Drupal/rdf/Tests/Field/FieldRdfaDatatypeCallbackTest.php
@@ -57,7 +57,7 @@ public function setUp() {
    */
   public function testDefaultFormatter() {
     // Expected value is the output of the datatype callback, not the raw value.
-    $this->assertFormatterRdfa('text_default', 'http://schema.org/interactionCount', 'foo' . $this->test_value);
+    $this->assertFormatterRdfa(array('type'=>'text_default'), 'http://schema.org/interactionCount', array('value' => 'foo' . $this->test_value));
   }
 
 }
diff --git a/core/modules/rdf/lib/Drupal/rdf/Tests/Field/FieldRdfaTestBase.php b/core/modules/rdf/lib/Drupal/rdf/Tests/Field/FieldRdfaTestBase.php
index 5afeeab..5fc4fe6 100644
--- a/core/modules/rdf/lib/Drupal/rdf/Tests/Field/FieldRdfaTestBase.php
+++ b/core/modules/rdf/lib/Drupal/rdf/Tests/Field/FieldRdfaTestBase.php
@@ -58,34 +58,33 @@ public function setUp() {
   /**
    * Helper function to test the formatter's RDFa.
    *
-   * @param string $formatter
-   *   The machine name of the formatter to test.
+   * @param array $formatter
+   *   An associative array describing the formatter to test and its settings
+   *   containing:
+   *   - type: The machine name of the field formatter to test.
+   *   - settings: The settings of the field formatter to test.
    * @param string $property
    *   The property that should be found.
-   * @param string $value
-   *   The expected value of the property.
-   * @param string $object_type
-   *   The object's type, either 'uri' or 'literal'.
-   * @param string $datatype
-   *   The data type of the property.
+   * @param array $expected_rdf_value
+   *   An associative array describing the expected value of the property
+   *   containing:
+   *   - value: The actual value of the string or URI.
+   *   - type: The type of RDF value, e.g. 'literal' for a string, or 'uri'.
+   *   Defaults to 'literal'.
+   *   - datatype: (optional) The datatype of the value (e.g. xsd:dateTime).
    */
-  protected function assertFormatterRdfa($formatter, $property, $value, $object_type = 'literal', $datatype = '') {
+  protected function assertFormatterRdfa($formatter, $property, $expected_rdf_value) {
+    // Merge in the default value type of "literal" if one wasn't given.
+    $expected_rdf_value += array('type' => 'literal');
     // The field formatter will be rendered inside the entity. Set the field
     // formatter in the entity display options before rendering the entity.
     entity_get_display('entity_test', 'entity_test', 'default')
-      ->setComponent($this->fieldName, array('type' => $formatter))
+      ->setComponent($this->fieldName, $formatter)
       ->save();
     $build = entity_view($this->entity, 'default');
     $output = drupal_render($build);
     $graph = new \EasyRdf_Graph($this->uri, $output, 'rdfa');
-    $expected_value = array(
-      'type' => $object_type,
-      'value' => $value,
-    );
-    if ($datatype) {
-      $expected_value['datatype'] = $datatype;
-    }
-    $this->assertTrue($graph->hasProperty($this->uri, $property, $expected_value), "Formatter $formatter exposes data correctly for {$this->fieldType} fields.");
+    $this->assertTrue($graph->hasProperty($this->uri, $property, $expected_rdf_value), "Formatter {$formatter['type']} exposes data correctly for {$this->fieldType} fields.");
   }
 
   /**
diff --git a/core/modules/rdf/lib/Drupal/rdf/Tests/Field/LinkFieldRdfaTest.php b/core/modules/rdf/lib/Drupal/rdf/Tests/Field/LinkFieldRdfaTest.php
new file mode 100644
index 0000000..176f862
--- /dev/null
+++ b/core/modules/rdf/lib/Drupal/rdf/Tests/Field/LinkFieldRdfaTest.php
@@ -0,0 +1,146 @@
+<?php
+/**
+ * @file
+ * Contains \Drupal\rdf\Tests\Field\LinkFieldRdfaTest.
+ */
+
+namespace Drupal\rdf\Tests\Field;
+
+use Drupal\rdf\Tests\Field\FieldRdfaTestBase;
+
+/**
+ * Tests the placement of RDFa in link field formatters.
+ */
+class LinkFieldRdfaTest extends FieldRdfaTestBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  protected $fieldType = 'link';
+
+  /**
+   * {@inheritdoc}
+   */
+  public static $modules = array('link', 'text');
+
+  public static function getInfo() {
+    return array(
+      'name'  => 'Field formatter: link',
+      'description'  => 'Tests RDFa output by link field formatters.',
+      'group' => 'RDF',
+    );
+  }
+
+  public function setUp() {
+    parent::setUp();
+
+    $this->createTestField();
+
+    // Add the mapping.
+    $mapping = rdf_get_mapping('entity_test', 'entity_test');
+    $mapping->setFieldMapping($this->fieldName, array(
+      'properties' => array('schema:link'),
+    ))->save();
+
+    // Set up test values.
+    $this->testValue = 'http://test.me';
+    $this->entity = entity_create('entity_test', array());
+    $this->entity->{$this->fieldName}->url = $this->testValue;
+  }
+
+  /**
+   * Tests all link formatters.
+   */
+  public function testAllFormatters() {
+    // set up the expected result
+    $expected_rdf = array(
+      'value' => $this->testValue,
+      'type' => 'uri',
+    );
+
+    // Test the link formatters with different options and settings.
+    // Test the link formatter: trim at 80, no other settings
+    $formatter = array(
+      'type' => 'link',
+      'settings' => array(
+        'trim_length' => 80,
+        'url_only' => FALSE,
+        'url_plain' => FALSE,
+        'rel' => '',
+        'target' => '',
+      ),
+    );
+    $this->assertFormatterRdfa($formatter, 'http://schema.org/link', $expected_rdf);
+
+    // Test the link formatter: trim at 40, nofollow, new window
+    $formatter = array(
+      'type' => 'link',
+      'settings' => array(
+        'trim_length' => 40,
+        'url_only' => FALSE,
+        'url_plain' => FALSE,
+        'rel' => 'nofollow',
+        'target' => '_blank',
+      ),
+    );
+    $this->assertFormatterRdfa($formatter, 'http://schema.org/link', $expected_rdf);
+
+    // Test the link formatter: trim at 40, URL only (not plaintext) nofollow, new window
+    $formatter = array(
+      'type' => 'link',
+      'settings' => array(
+        'trim_length' => 40,
+        'url_only' => TRUE,
+        'url_plain' => FALSE,
+        'rel' => 'nofollow',
+        'target' => '_blank',
+      ),
+    );
+    $this->assertFormatterRdfa($formatter, 'http://schema.org/link', $expected_rdf);
+
+    // Test the link_separate formatter: trim at 40, nofollow, new window
+    $formatter = array(
+      'type' => 'link_separate',
+      'settings' => array(
+        'trim_length' => 40,
+        'rel' => 'nofollow',
+        'target' => '_blank',
+      ),
+    );
+    $this->assertFormatterRdfa($formatter, 'http://schema.org/link', $expected_rdf);
+
+    // change the expected value here to literal. When formatted as plaintext
+    // then the RDF is expecting a 'literal' not a 'uri'
+    $expected_rdf = array(
+      'value' => $this->testValue,
+      'type' => 'literal',
+    );
+    // Test the link formatter: trim at 20, url only (as plaintext)
+    $formatter = array(
+      'type' => 'link',
+      'settings' => array(
+        'trim_length' => 20,
+        'url_only' => TRUE,
+        'url_plain' => TRUE,
+        'rel' => '0',
+        'target' => '0',
+      ),
+    );
+    $this->assertFormatterRdfa($formatter, 'http://schema.org/link', $expected_rdf);
+
+    // Test the link formatter: do not trim, url only (as plaintext)
+    $formatter = array(
+      'type' => 'link',
+      'settings' => array(
+        'trim_length' => 0,
+        'url_only' => TRUE,
+        'url_plain' => TRUE,
+        'rel' => '0',
+        'target' => '0',
+      ),
+    );
+    $this->assertFormatterRdfa($formatter, 'http://schema.org/link', $expected_rdf);
+
+  }
+
+}
diff --git a/core/modules/rdf/lib/Drupal/rdf/Tests/Field/TaxonomyTermReferenceRdfaTest.php b/core/modules/rdf/lib/Drupal/rdf/Tests/Field/TaxonomyTermReferenceRdfaTest.php
index 4e4f7a1..00ac9d7 100644
--- a/core/modules/rdf/lib/Drupal/rdf/Tests/Field/TaxonomyTermReferenceRdfaTest.php
+++ b/core/modules/rdf/lib/Drupal/rdf/Tests/Field/TaxonomyTermReferenceRdfaTest.php
@@ -103,7 +103,7 @@ public function setUp() {
    * Tests the plain formatter.
    */
   public function testPlainFormatter() {
-    $this->assertFormatterRdfa('taxonomy_term_reference_plain', 'http://schema.org/about', $this->term->getName(), 'literal');
+    $this->assertFormatterRdfa(array('type' => 'taxonomy_term_reference_plain'), 'http://schema.org/about', array('value' => $this->term->getName(), 'type' => 'literal'));
   }
 
   /**
@@ -111,7 +111,7 @@ public function testPlainFormatter() {
    */
   public function testLinkFormatter() {
     $term_uri = $this->getAbsoluteUri($this->term);
-    $this->assertFormatterRdfa('taxonomy_term_reference_link', 'http://schema.org/about', $term_uri, 'uri');
+    $this->assertFormatterRdfa(array('type'=>'taxonomy_term_reference_link'), 'http://schema.org/about', array('value' => $term_uri, 'type' => 'uri'));
   }
 
 }
diff --git a/core/modules/rdf/lib/Drupal/rdf/Tests/Field/TextFieldRdfaTest.php b/core/modules/rdf/lib/Drupal/rdf/Tests/Field/TextFieldRdfaTest.php
index d10318c..854c128 100644
--- a/core/modules/rdf/lib/Drupal/rdf/Tests/Field/TextFieldRdfaTest.php
+++ b/core/modules/rdf/lib/Drupal/rdf/Tests/Field/TextFieldRdfaTest.php
@@ -66,14 +66,14 @@ public function setUp() {
    * Tests the default formatter.
    */
   public function testDefaultFormatter() {
-    $this->assertFormatterRdfa('text_default', 'http://schema.org/text', $this->testValue);
+    $this->assertFormatterRdfa(array('type'=>'text_default'), 'http://schema.org/text', array('value' => $this->testValue));
   }
 
   /**
    * Tests the plain formatter.
    */
   public function testPlainFormatter() {
-    $this->assertFormatterRdfa('string', 'http://schema.org/text', $this->testValue);
+    $this->assertFormatterRdfa(array('type'=>'string'), 'http://schema.org/text', array('value' => $this->testValue));
   }
 
   /**
@@ -82,7 +82,7 @@ public function testPlainFormatter() {
    * @todo Check for the summary mapping.
    */
   public function testSummaryFormatter() {
-    $this->assertFormatterRdfa('text_summary_or_trimmed', 'http://schema.org/text', $this->testValue);
+    $this->assertFormatterRdfa(array('type'=>'text_summary_or_trimmed'), 'http://schema.org/text', array('value' => $this->testValue));
   }
 
   /**
@@ -91,6 +91,6 @@ public function testSummaryFormatter() {
    * @todo Check for the summary mapping.
    */
   public function testTrimmedFormatter() {
-    $this->assertFormatterRdfa('text_trimmed', 'http://schema.org/text', $this->testValue);
+    $this->assertFormatterRdfa(array('type'=>'text_trimmed'), 'http://schema.org/text', array('value' => $this->testValue));
   }
 }
