diff --git a/core/modules/system/tests/modules/form_test/form_test.routing.yml b/core/modules/system/tests/modules/form_test/form_test.routing.yml
index f8467ff..2940195 100644
--- a/core/modules/system/tests/modules/form_test/form_test.routing.yml
+++ b/core/modules/system/tests/modules/form_test/form_test.routing.yml
@@ -88,7 +88,7 @@ form_test.double_form:
 form_test.alter_form:
   path: '/form-test/alter'
   defaults:
-    _content: '\Drupal\form_test\Form\FormTestForm::alterForm'
+    _form: '\Drupal\form_test\Form\FormTestAlterForm'
     _title: 'Form altering test'
   requirements:
     _access: 'TRUE'
@@ -96,7 +96,7 @@ form_test.alter_form:
 form_test.validate_form:
   path: '/form-test/validate'
   defaults:
-    _content: '\Drupal\form_test\Form\FormTestForm::validateForm'
+    _form: '\Drupal\form_test\Form\FormTestValidateForm'
     _title: 'Form validation handlers test'
   requirements:
     _access: 'TRUE'
@@ -104,7 +104,7 @@ form_test.validate_form:
 form_test.validate_required:
   path: '/form-test/validate-required'
   defaults:
-    _content: '\Drupal\form_test\Form\FormTestForm::validateRequiredForm'
+    _form: '\Drupal\form_test\Form\FormTestValidateRequiredForm'
     _title: 'Form #required validation'
   requirements:
     _access: 'TRUE'
@@ -120,7 +120,7 @@ form_test.validate_required_no_title:
 form_test.validate_with_error_suppresion:
   path: '/form-test/limit-validation-errors'
   defaults:
-    _content: '\Drupal\form_test\Form\FormTestForm::validateFormWithErrorSuppression'
+    _form: '\Drupal\form_test\Form\FormTestLimitValidationErrorsForm'
     _title: 'Form validation with some error suppression'
   requirements:
     _access: 'TRUE'
@@ -128,7 +128,7 @@ form_test.validate_with_error_suppresion:
 form_test.pattern:
   path: '/form-test/pattern'
   defaults:
-    _content: '\Drupal\form_test\Form\FormTestForm::validatePattern'
+    _form: '\Drupal\form_test\Form\FormTestPatternForm'
     _title: 'Pattern validation'
   requirements:
     _access: 'TRUE'
@@ -224,7 +224,7 @@ form_test.select:
 form_test.empty_select:
   path: '/form-test/empty-select'
   defaults:
-    _content: '\Drupal\form_test\Form\FormTestForm::testEmptySelect'
+    _form: '\Drupal\form_test\Form\FormTestEmptySelect'
     _title: 'Empty Select Element'
   requirements:
     _access: 'TRUE'
@@ -280,7 +280,7 @@ form_test.range_invalid:
 form_test.color:
   path: '/form-test/color'
   defaults:
-    _content: '\Drupal\form_test\Form\FormTestForm::testColor'
+    _form: '\Drupal\form_test\Form\FormTestColor'
     _title: 'Color'
   requirements:
     _access: 'TRUE'
@@ -288,7 +288,7 @@ form_test.color:
 form_test.checkboxes_radios:
   path: '/form-test/checkboxes-radios/{customize}'
   defaults:
-    _content: '\Drupal\form_test\Form\FormTestForm::testCheckboxesRadios'
+    _form: '\Drupal\form_test\Form\FormTestCheckboxesRadios'
     _title: 'Checkboxes, Radios'
     customize: FALSE
   requirements:
@@ -297,7 +297,7 @@ form_test.checkboxes_radios:
 form_test.email:
   path: '/form-test/email'
   defaults:
-    _content: '\Drupal\form_test\Form\FormTestForm::testEmail'
+    _form: '\Drupal\form_test\Form\FormTestEmail'
     _title: 'E-Mail fields'
   requirements:
     _access: 'TRUE'
@@ -361,7 +361,7 @@ form_test.state_persistence:
 form_test.clicked_button:
   path: '/form-test/clicked-button/{first}/{second}/{third}'
   defaults:
-    _content: '\Drupal\form_test\Form\FormTestForm::testClickedButton'
+    _form: '\Drupal\form_test\Form\FormTestClickedButton'
     _title: 'Clicked button test'
     first: NULL
     second: NULL
@@ -372,7 +372,7 @@ form_test.clicked_button:
 form_test.checkboxes_zero:
   path: '/form-test/checkboxes-zero/{json}'
   defaults:
-    _content: '\Drupal\form_test\Form\FormTestForm::testCheckboxesZero'
+    _form: '\Drupal\form_test\Form\FormTestCheckboxesZero'
     _title: 'FAPI test involving checkboxes and zero'
     json: TRUE
   requirements:
@@ -389,7 +389,7 @@ form_test.required:
 form_test.button_class:
   path: '/form-test/button-class'
   defaults:
-    _content: '\Drupal\form_test\Form\FormTestForm::testButtonClass'
+    _form: '\Drupal\form_test\Form\FormTestButtonClass'
     _title: 'Button class testing'
   requirements:
     _access: 'TRUE'
diff --git a/core/modules/system/tests/modules/form_test/lib/Drupal/form_test/Form/FormTestLimitValidationErrorsForm.php b/core/modules/system/tests/modules/form_test/lib/Drupal/form_test/Form/FormTestLimitValidationErrorsForm.php
new file mode 100644
index 0000000..09f18d8
--- /dev/null
+++ b/core/modules/system/tests/modules/form_test/lib/Drupal/form_test/Form/FormTestLimitValidationErrorsForm.php
@@ -0,0 +1,122 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\form_test\Form\FormTestLimitValidationErrorsForm.
+ */
+
+namespace Drupal\form_test\Form;
+
+use Drupal\Core\Form\FormBase;
+
+/**
+ *Generate form of id form_test_limit_validation_errors_form.
+ *Builds a simple form with a button triggering partial validation.
+ */
+class FormTestLimitValidationErrorsForm extends FormBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getFormId() {
+    return 'form_test_limit_validation_errors_form';
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function buildForm(array $form, array &$form_state) {
+   $form['title'] = array(
+    '#type' => 'textfield',
+    '#title' => 'Title',
+    '#required' => TRUE,
+    );
+
+   $form['test'] = array(
+    '#title' => 'Test',
+    '#type' => 'textfield',
+    '#element_validate' => array(
+      'Drupal\form_test\Form\FormTestLimitValidationErrorsForm::elementValidateTest'
+      ),
+    );
+   $form['test_numeric_index'] = array(
+    '#tree' => TRUE,
+    );
+   $form['test_numeric_index'][0] = array(
+    '#title' => 'Test (numeric index)',
+    '#type' => 'textfield',
+    '#element_validate' => array(
+      'Drupal\form_test\Form\FormTestLimitValidationErrorsForm::elementValidateTest'
+      ),
+    );
+
+   $form['test_substring'] = array(
+    '#tree' => TRUE,
+    );
+   $form['test_substring']['foo'] = array(
+    '#title' => 'Test (substring) foo',
+    '#type' => 'textfield',
+    '#element_validate' => array(
+      'Drupal\form_test\Form\FormTestLimitValidationErrorsForm::elementValidateTest'
+      ),
+    );
+   $form['test_substring']['foobar'] = array(
+    '#title' => 'Test (substring) foobar',
+    '#type' => 'textfield',
+    '#element_validate' => array(
+      'Drupal\form_test\Form\FormTestLimitValidationErrorsForm::elementValidateTest'
+      ),
+    );
+
+   $form['actions']['partial'] = array(
+    '#type' => 'submit',
+    '#limit_validation_errors' => array(array('test')),
+    '#submit' => array('Drupal\form_test\Form\FormTestLimitValidationErrorsForm::formPartialSubmit'),
+    '#value' => t('Partial validate'),
+    );
+   $form['actions']['partial_numeric_index'] = array(
+    '#type' => 'submit',
+    '#limit_validation_errors' => array(array('test_numeric_index', 0)),
+    '#submit' => array('Drupal\form_test\Form\FormTestLimitValidationErrorsForm::formPartialSubmit'),
+    '#value' => t('Partial validate (numeric index)'),
+    );
+   $form['actions']['substring'] = array(
+    '#type' => 'submit',
+    '#limit_validation_errors' => array(array('test_substring', 'foo')),
+    '#submit' => array('Drupal\form_test\Form\FormTestLimitValidationErrorsForm::formPartialSubmit'),
+    '#value' => t('Partial validate (substring)'),
+    );
+   $form['actions']['full'] = array(
+    '#type' => 'submit',
+    '#value' => t('Full validate'),
+    );
+   return $form;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function submitForm(array &$form, array &$form_state) {
+
+  }
+
+  /**
+  * Form element validation handler for the 'test' element.
+  */
+  public static function elementValidateTest(&$element, &$form_state) {
+    if ($element['#value'] == 'invalid') {
+      form_error($element, $form_state, t('@label element is invalid', array('@label' => $element['#title'])));
+    }
+  }
+
+  /**
+  * Form submit handler for the partial validation submit button.
+  */
+  public static function formPartialSubmit($form, $form_state) {
+    // The title has not been validated, thus its value - in case of the test case
+    // an empty string - may not be set.
+    if (!isset($form_state['values']['title']) && isset($form_state['values']['test'])) {
+      drupal_set_message('Only validated values appear in the form values.');
+    }
+  }
+}
diff --git a/core/modules/system/tests/modules/form_test/lib/Drupal/form_test/Form/FormTestPatternForm.php b/core/modules/system/tests/modules/form_test/lib/Drupal/form_test/Form/FormTestPatternForm.php
new file mode 100644
index 0000000..87fc5cb
--- /dev/null
+++ b/core/modules/system/tests/modules/form_test/lib/Drupal/form_test/Form/FormTestPatternForm.php
@@ -0,0 +1,67 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\form_test\Form\FormTestPatternForm.
+ */
+
+namespace Drupal\form_test\Form;
+
+use Drupal\Core\Form\FormBase;
+
+/**
+ *Generate form of id form_test_pattern_form.
+ *Builds a simple form using the FAPI #pattern proterty.
+ */
+class FormTestPatternForm extends FormBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getFormId() {
+    return 'form_test_pattern_form';
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function buildForm(array $form, array &$form_state) {
+   $form['textfield'] = array(
+    '#type' => 'textfield',
+    '#title' => 'One digit followed by lowercase letters',
+    '#pattern' => '[0-9][a-z]+',
+    );
+   $form['tel'] = array(
+    '#type' => 'tel',
+    '#title' => 'Everything except numbers',
+    '#pattern' => '[^\d]*',
+    );
+   $form['password'] = array(
+    '#type' => 'password',
+    '#title' => 'Password',
+    '#pattern' => '[01]+',
+    );
+   $form['url'] = array(
+    '#type' => 'url',
+    '#title' => 'Client side validation',
+    '#decription' => 'Just client side validation, using the #pattern attribute.',
+    '#attributes' => array(
+      'pattern' => '.*foo.*',
+      ),
+    '#pattern' => 'ignored',
+    );
+   $form['submit'] = array(
+    '#type' => 'submit',
+    '#value' => 'Submit',
+    );
+   return $form;
+ }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function submitForm(array &$form, array &$form_state) {
+
+  }
+
+}
diff --git a/core/modules/system/tests/modules/form_test/lib/Drupal/form_test/Form/FormTestValidateForm.php b/core/modules/system/tests/modules/form_test/lib/Drupal/form_test/Form/FormTestValidateForm.php
new file mode 100644
index 0000000..6d8ddbb
--- /dev/null
+++ b/core/modules/system/tests/modules/form_test/lib/Drupal/form_test/Form/FormTestValidateForm.php
@@ -0,0 +1,73 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\form_test\Form\FormTestValidateForm.
+ */
+
+namespace Drupal\form_test\Form;
+
+use Drupal\Core\Form\FormBase;
+use Drupal\form_test\Callbacks;
+
+/**
+ *Generate form of id form_test_validate_form.
+ */
+class FormTestValidateForm extends FormBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getFormId() {
+    return 'form_test_validate_form';
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function buildForm(array $form, array &$form_state) {
+    $object = new Callbacks();
+
+    $form['name'] = array(
+      '#type' => 'textfield',
+      '#title' => 'Name',
+      '#default_value' => '',
+      '#element_validate' => array(array($object, 'validateName')),
+      );
+    $form['submit'] = array(
+      '#type' => 'submit',
+      '#value' => 'Save',
+      );
+
+  // To simplify this test, enable form caching and use form storage to
+  // remember our alteration.
+    $form_state['cache'] = TRUE;
+
+    return $form;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function submitForm(array &$form, array &$form_state) {
+
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function validateForm(array &$form, array &$form_state) {
+    if ($form_state['values']['name'] == 'validate') {
+    // Alter the form element.
+      $form['name']['#value'] = '#value changed by #validate';
+    // Alter the submitted value in $form_state.
+      form_set_value($form['name'], 'value changed by form_set_value() in #validate', $form_state);
+    // Output the element's value from $form_state.
+      drupal_set_message(t('@label value: @value', array('@label' => $form['name']['#title'], '@value' => $form_state['values']['name'])));
+
+    // Trigger a form validation error to see our changes.
+      form_set_error('', $form_state);
+    }
+  }
+
+}
diff --git a/core/modules/system/tests/modules/form_test/lib/Drupal/form_test/Form/FormTestValidateRequiredForm.php b/core/modules/system/tests/modules/form_test/lib/Drupal/form_test/Form/FormTestValidateRequiredForm.php
new file mode 100644
index 0000000..690a92e
--- /dev/null
+++ b/core/modules/system/tests/modules/form_test/lib/Drupal/form_test/Form/FormTestValidateRequiredForm.php
@@ -0,0 +1,93 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\form_test\Form\FormTestValidateRequiredForm.
+ */
+
+namespace Drupal\form_test\Form;
+
+use Drupal\Core\Form\FormBase;
+
+/**
+ *Generate form of id form_test_validate_required_form.
+ *Form to test the #required property.
+ */
+class FormTestValidateRequiredForm extends FormBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getFormId() {
+    return 'form_test_validate_required_form';
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function buildForm(array $form, array &$form_state) {
+   $options = drupal_map_assoc(array('foo', 'bar'));
+   $validate = array('form_test_validate_required_form_element_validate');
+
+   $form['textfield'] = array(
+    '#type' => 'textfield',
+    '#title' => 'Name',
+    '#required' => TRUE,
+    '#required_error' => t('Please enter a name.'),
+    );
+   $form['checkboxes'] = array(
+    '#type' => 'checkboxes',
+    '#title' => 'Checkboxes',
+    '#options' => $options,
+    '#required' => TRUE,
+    '#form_test_required_error' => t('Please choose at least one option.'),
+    '#element_validate' => $validate,
+    );
+   $form['select'] = array(
+    '#type' => 'select',
+    '#title' => 'Select',
+    '#options' => $options,
+    '#required' => TRUE,
+    '#form_test_required_error' => t('Please select something.'),
+    '#element_validate' => $validate,
+    );
+   $form['radios'] = array(
+    '#type' => 'radios',
+    '#title' => 'Radios',
+    '#options' => $options,
+    '#required' => TRUE,
+    );
+   $form['radios_optional'] = array(
+    '#type' => 'radios',
+    '#title' => 'Radios (optional)',
+    '#options' => $options,
+    );
+   $form['radios_optional_default_value_false'] = array(
+    '#type' => 'radios',
+    '#title' => 'Radios (optional, with a default value of FALSE)',
+    '#options' => $options,
+    '#default_value' => FALSE,
+    );
+   $form['actions'] = array('#type' => 'actions');
+   $form['actions']['submit'] = array('#type' => 'submit', '#value' => 'Submit');
+   return $form;
+ }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function submitForm(array &$form, array &$form_state) {
+    drupal_set_message('The form_test_validate_required_form form was submitted successfully.');
+  }
+
+  /**
+   *Form validation handler for the form_test_clicked_button() form.
+   */
+  public function validateForm(array &$form, array &$form_state) {
+    // Set a custom validation error on the #required element.
+    if (!empty($element['#required_but_empty']) && isset($element['#form_test_required_error'])) {
+      form_error($element, $form_state, $element['#form_test_required_error']);
+    }
+  }
+
+}
