diff --git a/core/includes/common.inc b/core/includes/common.inc
index 79b2224..456b820 100644
--- a/core/includes/common.inc
+++ b/core/includes/common.inc
@@ -3097,6 +3097,7 @@ function drupal_pre_render_html_tag($element) {
 function drupal_pre_render_link($element) {
   // By default, link options to pass to l() are normally set in #options.
   $element += array('#options' => array());
+
   // However, within the scope of renderable elements, #attributes is a valid
   // way to specify attributes, too. Take them into account, but do not override
   // attributes from #options.
@@ -3105,6 +3106,17 @@ function drupal_pre_render_link($element) {
     $element['#options']['attributes'] += $element['#attributes'];
   }
 
+  // Support for button links.
+  // Setting #button_type on #type 'link' to an empty string adds the .button
+  // class only, unless a more specific #button_type has been specified.
+  // @see form_pre_render_button()
+  if (isset($element['#button_type'])) {
+    $element['#options']['attributes']['class'][] = 'button';
+    if (!empty($element['#button_type'])) {
+      $element['#options']['attributes']['class'][] = 'button--' . $element['#button_type'];
+    }
+  }
+
   // This #pre_render callback can be invoked from inside or outside of a Form
   // API context, and depending on that, a HTML ID may be already set in
   // different locations. #options should have precedence over Form API's #id.
diff --git a/core/lib/Drupal/Core/Entity/EntityForm.php b/core/lib/Drupal/Core/Entity/EntityForm.php
index dcb9aae..ec49776 100644
--- a/core/lib/Drupal/Core/Entity/EntityForm.php
+++ b/core/lib/Drupal/Core/Entity/EntityForm.php
@@ -229,9 +229,7 @@ protected function actions(array $form, array &$form_state) {
         '#type' => 'link',
         '#title' => $this->t('Delete'),
         '#access' => $this->entity->access('delete'),
-        '#attributes' => array(
-          'class' => array('button', 'button--danger'),
-        ),
+        '#button_type' => 'danger',
       );
       $actions['delete'] += $route_info->toRenderArray();
     }
diff --git a/core/modules/system/lib/Drupal/system/Tests/Render/LinkTest.php b/core/modules/system/lib/Drupal/system/Tests/Render/LinkTest.php
new file mode 100644
index 0000000..a8b58a8
--- /dev/null
+++ b/core/modules/system/lib/Drupal/system/Tests/Render/LinkTest.php
@@ -0,0 +1,51 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\system\Tests\Render\LinkTest.
+ */
+
+namespace Drupal\system\Tests\Render;
+
+/**
+ * Tests rendering of #type link.
+ */
+class LinkTest extends RenderTestBase {
+
+  public static function getInfo() {
+    return array(
+      'name' => '#type link',
+      'description' => 'Tests rendering of #type link.',
+      'group' => 'Render',
+    );
+  }
+
+  /**
+   * Tests #button_type.
+   */
+  function testButtonType() {
+    $this->render(array(
+      '#type' => 'link',
+      '#title' => 'No button',
+      '#href' => '',
+    ));
+    $this->assertNoRaw('class');
+
+    $this->render(array(
+      '#type' => 'link',
+      '#title' => 'Button',
+      '#href' => '',
+      '#button_type' => '',
+    ));
+    $this->assertRaw('class="button"');
+
+    $this->render(array(
+      '#type' => 'link',
+      '#title' => 'Specific type',
+      '#href' => '',
+      '#button_type' => 'danger',
+    ));
+    $this->assertRaw('class="button button--danger"');
+  }
+
+}
diff --git a/core/modules/system/lib/Drupal/system/Tests/Render/RenderTestBase.php b/core/modules/system/lib/Drupal/system/Tests/Render/RenderTestBase.php
new file mode 100644
index 0000000..93243c2
--- /dev/null
+++ b/core/modules/system/lib/Drupal/system/Tests/Render/RenderTestBase.php
@@ -0,0 +1,85 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\system\Tests\Render\RenderTestBase.
+ */
+
+namespace Drupal\system\Tests\Render;
+
+use Drupal\Component\Utility\String;
+use Drupal\simpletest\DrupalUnitTestBase;
+
+/**
+ * Base test class for render element type tests.
+ */
+abstract class RenderTestBase extends DrupalUnitTestBase {
+
+  /**
+   * Modules to enable.
+   *
+   * @var array
+   */
+  public static $modules = array('system');
+
+  /**
+   * The rendered content.
+   *
+   * @var string
+   */
+  protected $content;
+
+  /**
+   * Renders a render array.
+   *
+   * @param array $elements
+   *   The elements to render.
+   *
+   * @return string
+   *   The rendered string.
+   */
+  protected function render(array $elements) {
+    $this->content = drupal_render($elements);
+    $this->verbose('<pre style="white-space: pre-wrap">' . String::checkPlain($this->content));
+    return $this->content;
+  }
+
+  /**
+   * Asserts that a given string is found literally in the raw rendered output.
+   *
+   * @param string $string
+   *   The string to find.
+   * @param string $message
+   *   (optional) The assertion message.
+   *
+   * @return bool
+   */
+  protected function assertRaw($string, $message = NULL) {
+    if (!isset($message)) {
+      $message = String::format('Raw string @value found.', array(
+        '@value' => var_export($string, TRUE),
+      ));
+    }
+    return $this->assert(strpos($this->content, $string) !== FALSE, $message);
+  }
+
+  /**
+   * Asserts that a given string is not found literally in the raw rendered output.
+   *
+   * @param string $string
+   *   The string to find.
+   * @param string $message
+   *   (optional) The assertion message.
+   *
+   * @return bool
+   */
+  protected function assertNoRaw($string, $message = NULL) {
+    if (!isset($message)) {
+      $message = String::format('Raw string @value not found.', array(
+        '@value' => var_export($string, TRUE),
+      ));
+    }
+    return $this->assert(strpos($this->content, $string) === FALSE, $message);
+  }
+
+}
