diff --git a/core/lib/Drupal/Core/EventSubscriber/RouteProcessorSubscriber.php b/core/lib/Drupal/Core/EventSubscriber/RouteProcessorSubscriber.php
index 0061530..f965360 100644
--- a/core/lib/Drupal/Core/EventSubscriber/RouteProcessorSubscriber.php
+++ b/core/lib/Drupal/Core/EventSubscriber/RouteProcessorSubscriber.php
@@ -38,8 +38,18 @@ public function __construct(ContentNegotiation $negotiation) {
   public function onRequestSetController(GetResponseEvent $event) {
     $request = $event->getRequest();
 
+    // @todo This should all get converted into one or more RouteEnhancers.
     if (!$request->attributes->has('_controller') && $this->negotiation->getContentType($request) === 'html') {
-      $request->attributes->set('_controller', '\Drupal\Core\HtmlPageController::content');
+      if ($request->attributes->has('_form')) {
+        $request->attributes->set('_controller', '\Drupal\Core\HtmlFormController::content');
+      }
+      elseif ($request->attributes->has('_content')) {
+        $request->attributes->set('_controller', '\Drupal\Core\HtmlPageController::content');
+      }
+      else {
+        throw new \InvalidArgumentException('No valid subcontroller key was found');
+      }
+
     }
   }
 
diff --git a/core/lib/Drupal/Core/HtmlFormController.php b/core/lib/Drupal/Core/HtmlFormController.php
new file mode 100644
index 0000000..b641341
--- /dev/null
+++ b/core/lib/Drupal/Core/HtmlFormController.php
@@ -0,0 +1,81 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\HtmlFormController.
+ */
+
+namespace Drupal\Core;
+
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpFoundation\Response;
+use Symfony\Component\DependencyInjection\ContainerAwareInterface;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+
+/**
+ * Wrapping controller for forms that serve as the main page body.
+ */
+class HtmlFormController implements ContainerAwareInterface {
+
+  /**
+   * The injection container for this object.
+   *
+   * @var \Symfony\Component\DependencyInjection\ContainerInterface
+   */
+  protected $container;
+
+  /**
+   * Injects the service container used by this object.
+   *
+   * @param \Symfony\Component\DependencyInjection\ContainerInterface $container
+   *   The service container this object should use.
+   */
+  public function setContainer(ContainerInterface $container = NULL) {
+    $this->container = $container;
+  }
+
+  /**
+   * Controller method for generic HTML form pages.
+   *
+   * @param \Symfony\Component\HttpFoundation\Request $request
+   *   The request object.
+   * @param callable $_form
+   *   The name of the form class for this request.
+   *
+   * @return \Symfony\Component\HttpFoundation\Response
+   *   A response object.
+   */
+  public function content(Request $request, $_form) {
+    // If this is a class, instantiate it.
+    if (class_exists($_form)) {
+      if (in_array('Drupal\Core\ControllerInterface', class_implements($_form))) {
+        $form_arg = $_form::create($this->container);
+      }
+      else {
+        $form_arg = new $_form();
+      }
+    }
+    // Otherwise, it is a service.
+    else {
+      $form_arg = $this->container->get($_form);
+    }
+
+    // Using reflection, find all of the parameters needed by the form in the
+    // request attributes, skipping $form and $form_state.
+    $attributes = $request->attributes->all();
+    $reflection = new \ReflectionMethod($form_arg, 'buildForm');
+    $params = $reflection->getParameters();
+    $args = array();
+    foreach (array_splice($params, 2) as $param) {
+      if (array_key_exists($param->name, $attributes)) {
+        $args[] = $attributes[$param->name];
+      }
+    }
+    $form_state['build_info']['args'] = $args;
+
+    $form_id = _drupal_form_id($form_arg, $form_state);
+    $form = drupal_build_form($form_id, $form_state);
+    return new Response(drupal_render_page($form));
+  }
+
+}
diff --git a/core/modules/system/lib/Drupal/system/Tests/Form/FormObjectTest.php b/core/modules/system/lib/Drupal/system/Tests/Form/FormObjectTest.php
index cf2fe24..39a9b86 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Form/FormObjectTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Form/FormObjectTest.php
@@ -47,13 +47,48 @@ protected function setUp() {
    * Tests using an object as the form callback.
    */
   function testObjectFormCallback() {
+    $config_factory = $this->container->get('config.factory');
+
     $this->drupalGet('form-test/object-builder');
     $this->assertText('The FormTestObject::buildForm() method was used for this form.');
     $elements = $this->xpath('//form[@id="form-test-form-test-object"]');
     $this->assertTrue(!empty($elements), 'The correct form ID was used.');
-    $this->drupalPost('form-test/object-builder', NULL, t('Save'));
+    $this->drupalPost(NULL, array('bananas' => 'green'), t('Save'));
     $this->assertText('The FormTestObject::validateForm() method was used for this form.');
     $this->assertText('The FormTestObject::submitForm() method was used for this form.');
+    $value = $config_factory->get('form_test.object')->get('bananas');
+    $this->assertIdentical('green', $value);
+
+    $this->drupalGet('form-test/object-arguments-builder/yellow');
+    $this->assertText('The FormTestArgumentsObject::buildForm() method was used for this form.');
+    $elements = $this->xpath('//form[@id="form-test-form-test-arguments-object"]');
+    $this->assertTrue(!empty($elements), 'The correct form ID was used.');
+    $this->drupalPost(NULL, NULL, t('Save'));
+    $this->assertText('The FormTestArgumentsObject::validateForm() method was used for this form.');
+    $this->assertText('The FormTestArgumentsObject::submitForm() method was used for this form.');
+    $value = $config_factory->get('form_test.object')->get('bananas');
+    $this->assertIdentical('yellow', $value);
+
+    $this->drupalGet('form-test/object-service-builder');
+    $this->assertText('The FormTestServiceObject::buildForm() method was used for this form.');
+    $elements = $this->xpath('//form[@id="form-test-form-test-service-object"]');
+    $this->assertTrue(!empty($elements), 'The correct form ID was used.');
+    $this->drupalPost(NULL, array('bananas' => 'brown'), t('Save'));
+    $this->assertText('The FormTestServiceObject::validateForm() method was used for this form.');
+    $this->assertText('The FormTestServiceObject::submitForm() method was used for this form.');
+    $value = $config_factory->get('form_test.object')->get('bananas');
+    $this->assertIdentical('brown', $value);
+
+    $this->drupalGet('form-test/object-controller-builder');
+    $this->assertText('The FormTestControllerObject::create() method was used for this form.');
+    $this->assertText('The FormTestControllerObject::buildForm() method was used for this form.');
+    $elements = $this->xpath('//form[@id="form-test-form-test-controller-object"]');
+    $this->assertTrue(!empty($elements), 'The correct form ID was used.');
+    $this->drupalPost(NULL, array('bananas' => 'black'), t('Save'));
+    $this->assertText('The FormTestControllerObject::validateForm() method was used for this form.');
+    $this->assertText('The FormTestControllerObject::submitForm() method was used for this form.');
+    $value = $config_factory->get('form_test.object')->get('bananas');
+    $this->assertIdentical('black', $value);
   }
 
 }
diff --git a/core/modules/system/tests/modules/condition_test/condition_test.routing.yml b/core/modules/system/tests/modules/condition_test/condition_test.routing.yml
index 96fbdca..d242511 100644
--- a/core/modules/system/tests/modules/condition_test/condition_test.routing.yml
+++ b/core/modules/system/tests/modules/condition_test/condition_test.routing.yml
@@ -1,6 +1,6 @@
 condition_test_1:
   pattern: '/condition_test'
   defaults:
-    _controller: '\Drupal\condition_test\FormController::getForm'
+    _form: '\Drupal\condition_test\FormController'
   requirements:
     _access: 'TRUE'
diff --git a/core/modules/system/tests/modules/condition_test/lib/Drupal/condition_test/FormController.php b/core/modules/system/tests/modules/condition_test/lib/Drupal/condition_test/FormController.php
index 03b918e..93c3603 100644
--- a/core/modules/system/tests/modules/condition_test/lib/Drupal/condition_test/FormController.php
+++ b/core/modules/system/tests/modules/condition_test/lib/Drupal/condition_test/FormController.php
@@ -30,12 +30,11 @@ public function getFormID() {
   }
 
   /**
-   * Provides a simple method the router can fire in order to invoke this form.
+   * Constructs a \Drupal\condition_test\FormController object.
    */
-  public function getForm() {
+  public function __construct() {
     $manager = new ConditionManager(drupal_container()->getParameter('container.namespaces'));
     $this->condition = $manager->createInstance('node_type');
-    return drupal_get_form($this);
   }
 
   /**
diff --git a/core/modules/system/tests/modules/form_test/form_test.module b/core/modules/system/tests/modules/form_test/form_test.module
index fe5d999..3a0ecaf 100644
--- a/core/modules/system/tests/modules/form_test/form_test.module
+++ b/core/modules/system/tests/modules/form_test/form_test.module
@@ -28,12 +28,6 @@ function form_test_menu() {
     'access callback' => TRUE,
     'type' => MENU_CALLBACK,
   );
-  $items['form-test/object-builder'] = array(
-    'title' => 'Form object builder test',
-    'page callback' => 'form_test_object_builder',
-    'access callback' => TRUE,
-    'type' => MENU_CALLBACK,
-  );
   $items['form-test/system-config-form'] = array(
     'title' => 'Form object builder test',
     'page callback' => 'form_test_system_config_form',
@@ -377,13 +371,6 @@ function form_test_permission() {
 }
 
 /**
- * Page callback: Displays a form built from an object.
- */
-function form_test_object_builder() {
-  return drupal_get_form(new FormTestObject());
-}
-
-/**
  * Page callback: Displays a form built from SystemConfigForm.
  */
 function form_test_system_config_form() {
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
new file mode 100644
index 0000000..826e737
--- /dev/null
+++ b/core/modules/system/tests/modules/form_test/form_test.routing.yml
@@ -0,0 +1,27 @@
+form_test.route1:
+  pattern: '/form-test/object-builder'
+  defaults:
+    _form: '\Drupal\form_test\FormTestObject'
+  requirements:
+    _access: 'TRUE'
+
+form_test.route2:
+  pattern: '/form-test/object-arguments-builder/{arg}'
+  defaults:
+    _form: '\Drupal\form_test\FormTestArgumentsObject'
+  requirements:
+    _access: 'TRUE'
+
+form_test.route3:
+  pattern: '/form-test/object-service-builder'
+  defaults:
+    _form: 'form_test.form.serviceForm'
+  requirements:
+    _access: 'TRUE'
+
+form_test.route4:
+  pattern: '/form-test/object-controller-builder'
+  defaults:
+    _form: '\Drupal\form_test\FormTestControllerObject'
+  requirements:
+    _access: 'TRUE'
diff --git a/core/modules/system/tests/modules/form_test/lib/Drupal/form_test/FormTestArgumentsObject.php b/core/modules/system/tests/modules/form_test/lib/Drupal/form_test/FormTestArgumentsObject.php
new file mode 100644
index 0000000..ee13968
--- /dev/null
+++ b/core/modules/system/tests/modules/form_test/lib/Drupal/form_test/FormTestArgumentsObject.php
@@ -0,0 +1,61 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\form_test\FormTestArgumentsObject.
+ */
+
+namespace Drupal\form_test;
+
+use Drupal\Core\Form\FormInterface;
+
+/**
+ * Provides a test form object that needs arguments.
+ */
+class FormTestArgumentsObject implements FormInterface {
+
+  /**
+   * Implements \Drupal\Core\Form\FormInterface::getFormID().
+   */
+  public function getFormID() {
+    return 'form_test_form_test_arguments_object';
+  }
+
+  /**
+   * Implements \Drupal\Core\Form\FormInterface::buildForm().
+   */
+  public function buildForm(array $form, array &$form_state, $arg = NULL) {
+    $form['element'] = array('#markup' => 'The FormTestArgumentsObject::buildForm() method was used for this form.');
+
+    $form['bananas'] = array(
+      '#type' => 'textfield',
+      '#default_value' => check_plain($arg),
+      '#title' => t('Bananas'),
+    );
+
+    $form['actions']['#type'] = 'actions';
+    $form['actions']['submit'] = array(
+      '#type' => 'submit',
+      '#value' => t('Save'),
+    );
+    return $form;
+  }
+
+  /**
+   * Implements \Drupal\Core\Form\FormInterface::validateForm().
+   */
+  public function validateForm(array &$form, array &$form_state) {
+    drupal_set_message(t('The FormTestArgumentsObject::validateForm() method was used for this form.'));
+  }
+
+  /**
+   * Implements \Drupal\Core\Form\FormInterface::submitForm().
+   */
+  public function submitForm(array &$form, array &$form_state) {
+    drupal_set_message(t('The FormTestArgumentsObject::submitForm() method was used for this form.'));
+    config('form_test.object')
+      ->set('bananas', $form_state['values']['bananas'])
+      ->save();
+  }
+
+}
diff --git a/core/modules/system/tests/modules/form_test/lib/Drupal/form_test/FormTestBundle.php b/core/modules/system/tests/modules/form_test/lib/Drupal/form_test/FormTestBundle.php
new file mode 100644
index 0000000..0ccf9d8
--- /dev/null
+++ b/core/modules/system/tests/modules/form_test/lib/Drupal/form_test/FormTestBundle.php
@@ -0,0 +1,26 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\form_test\FormTestndle.
+ */
+
+namespace Drupal\form_test;
+
+use Symfony\Component\DependencyInjection\ContainerBuilder;
+use Symfony\Component\HttpKernel\Bundle\Bundle;
+use Symfony\Component\DependencyInjection\Reference;
+
+/**
+ * Form test dependency injection container.
+ */
+class FormTestBundle extends Bundle {
+
+  /**
+   * Overrides \Symfony\Component\HttpKernel\Bundle\Bundle::build().
+   */
+  public function build(ContainerBuilder $container) {
+    $container->register('form_test.form.serviceForm', 'Drupal\form_test\FormTestServiceObject');
+  }
+
+}
diff --git a/core/modules/system/tests/modules/form_test/lib/Drupal/form_test/FormTestControllerObject.php b/core/modules/system/tests/modules/form_test/lib/Drupal/form_test/FormTestControllerObject.php
new file mode 100644
index 0000000..38a8fc7
--- /dev/null
+++ b/core/modules/system/tests/modules/form_test/lib/Drupal/form_test/FormTestControllerObject.php
@@ -0,0 +1,70 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\form_test\FormTestControllerObject.
+ */
+
+namespace Drupal\form_test;
+
+use Drupal\Core\Form\FormInterface;
+use Drupal\Core\ControllerInterface;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+
+/**
+ * Provides a test form object.
+ */
+class FormTestControllerObject implements FormInterface, ControllerInterface {
+
+  /**
+   * Implements \Drupal\Core\Form\FormInterface::getFormID().
+   */
+  public function getFormID() {
+    return 'form_test_form_test_controller_object';
+  }
+
+  /**
+   * Implements \Drupal\Core\ControllerInterface::create().
+   */
+  public static function create(ContainerInterface $container) {
+    drupal_set_message(t('The FormTestControllerObject::create() method was used for this form.'));
+    return new static();
+  }
+
+  /**
+   * Implements \Drupal\Core\Form\FormInterface::buildForm().
+   */
+  public function buildForm(array $form, array &$form_state) {
+    $form['element'] = array('#markup' => 'The FormTestControllerObject::buildForm() method was used for this form.');
+
+    $form['bananas'] = array(
+      '#type' => 'textfield',
+      '#title' => t('Bananas'),
+    );
+
+    $form['actions']['#type'] = 'actions';
+    $form['actions']['submit'] = array(
+      '#type' => 'submit',
+      '#value' => t('Save'),
+    );
+    return $form;
+  }
+
+  /**
+   * Implements \Drupal\Core\Form\FormInterface::validateForm().
+   */
+  public function validateForm(array &$form, array &$form_state) {
+    drupal_set_message(t('The FormTestControllerObject::validateForm() method was used for this form.'));
+  }
+
+  /**
+   * Implements \Drupal\Core\Form\FormInterface::submitForm().
+   */
+  public function submitForm(array &$form, array &$form_state) {
+    drupal_set_message(t('The FormTestControllerObject::submitForm() method was used for this form.'));
+    config('form_test.object')
+      ->set('bananas', $form_state['values']['bananas'])
+      ->save();
+  }
+
+}
diff --git a/core/modules/system/tests/modules/form_test/lib/Drupal/form_test/FormTestServiceObject.php b/core/modules/system/tests/modules/form_test/lib/Drupal/form_test/FormTestServiceObject.php
new file mode 100644
index 0000000..c7663ef
--- /dev/null
+++ b/core/modules/system/tests/modules/form_test/lib/Drupal/form_test/FormTestServiceObject.php
@@ -0,0 +1,61 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\form_test\FormTestServiceObject.
+ */
+
+namespace Drupal\form_test;
+
+use Drupal\Core\Form\FormInterface;
+
+/**
+ * Provides a test form object.
+ */
+class FormTestServiceObject implements FormInterface {
+
+  /**
+   * Implements \Drupal\Core\Form\FormInterface::getFormID().
+   */
+  public function getFormID() {
+    return 'form_test_form_test_service_object';
+  }
+
+  /**
+   * Implements \Drupal\Core\Form\FormInterface::buildForm().
+   */
+  public function buildForm(array $form, array &$form_state) {
+    $form['element'] = array('#markup' => 'The FormTestServiceObject::buildForm() method was used for this form.');
+
+    $form['bananas'] = array(
+      '#type' => 'textfield',
+      '#default_value' => 'brown',
+      '#title' => t('Bananas'),
+    );
+
+    $form['actions']['#type'] = 'actions';
+    $form['actions']['submit'] = array(
+      '#type' => 'submit',
+      '#value' => t('Save'),
+    );
+    return $form;
+  }
+
+  /**
+   * Implements \Drupal\Core\Form\FormInterface::validateForm().
+   */
+  public function validateForm(array &$form, array &$form_state) {
+    drupal_set_message(t('The FormTestServiceObject::validateForm() method was used for this form.'));
+  }
+
+  /**
+   * Implements \Drupal\Core\Form\FormInterface::submitForm().
+   */
+  public function submitForm(array &$form, array &$form_state) {
+    drupal_set_message(t('The FormTestServiceObject::submitForm() method was used for this form.'));
+    config('form_test.object')
+      ->set('bananas', $form_state['values']['bananas'])
+      ->save();
+  }
+
+}
diff --git a/core/modules/views/views_ui/lib/Drupal/views_ui/Form/BreakLockForm.php b/core/modules/views/views_ui/lib/Drupal/views_ui/Form/BreakLockForm.php
index d7f6d53..cc699b8 100644
--- a/core/modules/views/views_ui/lib/Drupal/views_ui/Form/BreakLockForm.php
+++ b/core/modules/views/views_ui/lib/Drupal/views_ui/Form/BreakLockForm.php
@@ -58,19 +58,6 @@ public static function create(ContainerInterface $container) {
   }
 
   /**
-   * Creates a new instance of this form.
-   *
-   * @param \Drupal\views\ViewStorageInterface $view
-   *   The view being acted upon.
-   *
-   * @return array
-   *   The built form array.
-   */
-  public function getForm(ViewStorageInterface $view) {
-    return drupal_get_form($this, $view);
-  }
-
-  /**
    * Implements \Drupal\Core\Form\FormInterface::getFormID().
    */
   public function getFormID() {
diff --git a/core/modules/views/views_ui/lib/Drupal/views_ui/Form/DeleteForm.php b/core/modules/views/views_ui/lib/Drupal/views_ui/Form/DeleteForm.php
index 3f38679..f9b7272 100644
--- a/core/modules/views/views_ui/lib/Drupal/views_ui/Form/DeleteForm.php
+++ b/core/modules/views/views_ui/lib/Drupal/views_ui/Form/DeleteForm.php
@@ -16,19 +16,6 @@
 class DeleteForm implements FormInterface {
 
   /**
-   * Creates a new instance of this form.
-   *
-   * @param \Drupal\views\ViewStorageInterface $view
-   *   The view being acted upon.
-   *
-   * @return array
-   *   The built form array.
-   */
-  public function getForm(ViewStorageInterface $view) {
-    return drupal_get_form($this, $view);
-  }
-
-  /**
    * Implements \Drupal\Core\Form\FormInterface::getFormID().
    */
   public function getFormID() {
diff --git a/core/modules/views/views_ui/lib/Drupal/views_ui/Form/SettingsFormBase.php b/core/modules/views/views_ui/lib/Drupal/views_ui/Form/SettingsFormBase.php
index 82ea585..662e00d 100644
--- a/core/modules/views/views_ui/lib/Drupal/views_ui/Form/SettingsFormBase.php
+++ b/core/modules/views/views_ui/lib/Drupal/views_ui/Form/SettingsFormBase.php
@@ -44,14 +44,4 @@ public static function create(ContainerInterface $container) {
     );
   }
 
-  /**
-   * Creates a new instance of this form.
-   *
-   * @return array
-   *   The built form array.
-   */
-  public function getForm() {
-    return drupal_get_form($this);
-  }
-
 }
diff --git a/core/modules/views/views_ui/views_ui.routing.yml b/core/modules/views/views_ui/views_ui.routing.yml
index ed81159..9c64891 100644
--- a/core/modules/views/views_ui/views_ui.routing.yml
+++ b/core/modules/views/views_ui/views_ui.routing.yml
@@ -15,14 +15,14 @@ views_ui.add:
 views_ui.settings.basic:
   pattern: '/admin/structure/views/settings'
   defaults:
-    _controller: '\Drupal\views_ui\Form\BasicSettingsForm::getForm'
+    _form: '\Drupal\views_ui\Form\BasicSettingsForm'
   requirements:
     _permission: 'administer views'
 
 views_ui.settings.advanced:
   pattern: '/admin/structure/views/settings/advanced'
   defaults:
-    _controller: '\Drupal\views_ui\Form\AdvancedSettingsForm::getForm'
+    _form: '\Drupal\views_ui\Form\AdvancedSettingsForm'
   requirements:
     _permission: 'administer views'
 
@@ -58,7 +58,7 @@ views_ui.clone:
 views_ui.delete:
   pattern: '/admin/structure/views/view/{view}/delete'
   defaults:
-    _controller: 'Drupal\views_ui\Form\DeleteForm::getForm'
+    _form: 'Drupal\views_ui\Form\DeleteForm'
   requirements:
     _permission: 'administer views'
 
@@ -104,7 +104,7 @@ views_ui.preview:
 views_ui.breakLock:
   pattern: '/admin/structure/views/view/{view}/break-lock'
   defaults:
-    _controller: '\Drupal\views_ui\Form\BreakLockForm::getForm'
+    _form: '\Drupal\views_ui\Form\BreakLockForm'
     display_id: NULL
   requirements:
     _permission: 'administer views'
