diff --git a/core/modules/forum/forum.module b/core/modules/forum/forum.module
index c5af0f4..90fec3d 100644
--- a/core/modules/forum/forum.module
+++ b/core/modules/forum/forum.module
@@ -632,6 +632,20 @@ function forum_form_taxonomy_term_form_alter(&$form, &$form_state, $form_id) {
  * Implements hook_form_BASE_FORM_ID_alter() for node_form().
  */
 function forum_form_node_form_alter(&$form, &$form_state, $form_id) {
+  $node = $form_state['controller']->getEntity();
+  if (isset($node->taxonomy_forums) && !$node->isNew()) {
+    $forum_terms = $node->taxonomy_forums;
+    // If editing, give option to leave shadows.
+    $shadow = (count($forum_terms) > 1);
+    $form['shadow'] = array(
+      '#type' => 'checkbox',
+      '#title' => t('Leave shadow copy'),
+      '#default_value' => $shadow,
+      '#description' => t('If you move this topic, you can leave a link in the old forum to the new forum.'),
+    );
+    $form['forum_tid'] = array('#type' => 'value', '#value' => $node->forum_tid);
+  }
+
   if (isset($form['taxonomy_forums'])) {
     $langcode = $form['taxonomy_forums']['#language'];
     // Make the vocabulary required for 'real' forum-nodes.
@@ -665,29 +679,6 @@ function forum_block_view_pre_render($elements) {
 }
 
 /**
- * Implements hook_form().
- */
-function forum_form(EntityInterface $node, &$form_state) {
-  $type = node_type_load($node->type);
-  $form['title'] = array(
-    '#type' => 'textfield',
-    '#title' => check_plain($type->title_label),
-    '#default_value' => !empty($node->title) ? $node->title : '',
-    '#required' => TRUE, '#weight' => -5
-  );
-
-  if (!empty($node->nid)) {
-    $forum_terms = $node->taxonomy_forums;
-    // If editing, give option to leave shadows.
-    $shadow = (count($forum_terms) > 1);
-    $form['shadow'] = array('#type' => 'checkbox', '#title' => t('Leave shadow copy'), '#default_value' => $shadow, '#description' => t('If you move this topic, you can leave a link in the old forum to the new forum.'));
-    $form['forum_tid'] = array('#type' => 'value', '#value' => $node->forum_tid);
-  }
-
-  return $form;
-}
-
-/**
  * Returns a tree of all forums for a given taxonomy term ID.
  *
  * @param $tid
diff --git a/core/modules/node/content_types.inc b/core/modules/node/content_types.inc
index f8b144a..156576b 100644
--- a/core/modules/node/content_types.inc
+++ b/core/modules/node/content_types.inc
@@ -22,46 +22,44 @@ function node_overview_types() {
 
   foreach ($names as $key => $name) {
     $type = $types[$key];
-    if (node_hook($type->type, 'form')) {
-      $row = array(theme('node_admin_overview', array('name' => $name, 'type' => $type)));
-      if ($field_ui && user_access('administer node fields')) {
-        $links['fields'] = array(
-          'title' => t('Manage fields'),
-          'href' => 'admin/structure/types/manage/' . $type->type . '/fields',
-          'weight' => 0,
-        );
-      }
-      if ($field_ui && user_access('administer node display')) {
-        $links['display'] = array(
-          'title' => t('Manage display'),
-          'href' => 'admin/structure/types/manage/' . $type->type . '/display',
-          'weight' => 5,
-        );
-      }
-
-      $links['edit'] = array(
-        'title' => t('Edit'),
-        'href' => 'admin/structure/types/manage/' . $type->type,
-        'weight' => 10,
+    $row = array(theme('node_admin_overview', array('name' => $name, 'type' => $type)));
+    if ($field_ui && user_access('administer node fields')) {
+      $links['fields'] = array(
+        'title' => t('Manage fields'),
+        'href' => 'admin/structure/types/manage/' . $type->type . '/fields',
+        'weight' => 0,
       );
-
-      if ($type->custom) {
-        $links['delete'] = array(
-          'title' => t('Delete'),
-          'href' => 'admin/structure/types/manage/' . $type->type . '/delete',
-          'weight' => 15,
-        );
-      }
-
-      $row[] = array(
-        'data' => array(
-          '#type' => 'operations',
-          '#links' => $links,
-        ),
+    }
+    if ($field_ui && user_access('administer node display')) {
+      $links['display'] = array(
+        'title' => t('Manage display'),
+        'href' => 'admin/structure/types/manage/' . $type->type . '/display',
+        'weight' => 5,
       );
+    }
+
+    $links['edit'] = array(
+      'title' => t('Edit'),
+      'href' => 'admin/structure/types/manage/' . $type->type,
+      'weight' => 10,
+    );
 
-      $rows[] = $row;
+    if ($type->custom) {
+      $links['delete'] = array(
+        'title' => t('Delete'),
+        'href' => 'admin/structure/types/manage/' . $type->type . '/delete',
+        'weight' => 15,
+      );
     }
+
+    $row[] = array(
+      'data' => array(
+        '#type' => 'operations',
+        '#links' => $links,
+      ),
+    );
+
+    $rows[] = $row;
   }
 
   $build['node_table'] = array(
diff --git a/core/modules/node/lib/Drupal/node/NodeFormController.php b/core/modules/node/lib/Drupal/node/NodeFormController.php
index 350b4e3..8a39e41 100644
--- a/core/modules/node/lib/Drupal/node/NodeFormController.php
+++ b/core/modules/node/lib/Drupal/node/NodeFormController.php
@@ -49,7 +49,6 @@ protected function prepareEntity() {
     // Always use the default revision setting.
     $node->setNewRevision(in_array('revision', $node_options));
 
-    node_invoke($node, 'prepare');
     module_invoke_all('node_prepare', $node);
   }
 
@@ -93,18 +92,16 @@ public function form(array $form, array &$form_state) {
       '#default_value' => isset($node->changed) ? $node->changed : NULL,
     );
 
-    // Invoke hook_form() to get the node-specific bits. Can't use node_invoke()
-    // because hook_form() needs to be able to receive $form_state by reference.
-    // @todo hook_form() implementations are unable to add #validate or #submit
-    //   handlers to the form buttons below. Remove hook_form() entirely.
-    $function = node_hook($node->type, 'form');
-    if ($function && ($extra = $function($node, $form_state))) {
-      $form = NestedArray::mergeDeep($form, $extra);
-    }
-    // If the node type has a title, and the node type form defined no special
-    // weight for it, we default to a weight of -5 for consistency.
-    if (isset($form['title']) && !isset($form['title']['#weight'])) {
-      $form['title']['#weight'] = -5;
+    $node_type = node_type_load($node->type);
+    if ($node_type->has_title) {
+      $form['title'] = array(
+        '#type' => 'textfield',
+        '#title' => check_plain($node_type->title_label),
+        '#required' => TRUE,
+        '#default_value' => $node->title,
+        '#maxlength' => 255,
+        '#weight' => -5,
+      );
     }
 
     $language_configuration = module_invoke('language', 'get_default_configuration', 'node', $node->type);
@@ -341,13 +338,9 @@ public function validate(array $form, array &$form_state) {
       form_set_error('date', t('You have to specify a valid date.'));
     }
 
-    // Invoke hook_validate() for node type specific validation and
-    // hook_node_validate() for miscellaneous validation needed by modules.
-    // Can't use node_invoke() or module_invoke_all(), because $form_state must
+    // Invoke hook_node_validate() for validation needed by modules.
+    // Can't use module_invoke_all(), because $form_state must
     // be receivable by reference.
-    if ($function = node_hook($node->type, 'validate')) {
-      $function($node, $form, $form_state);
-    }
     foreach (module_implements('node_validate') as $module) {
       $function = $module . '_node_validate';
       $function($node, $form, $form_state);
diff --git a/core/modules/node/lib/Drupal/node/NodeRenderController.php b/core/modules/node/lib/Drupal/node/NodeRenderController.php
index 6a6608a..05e13da 100644
--- a/core/modules/node/lib/Drupal/node/NodeRenderController.php
+++ b/core/modules/node/lib/Drupal/node/NodeRenderController.php
@@ -34,12 +34,6 @@ public function buildContent(array $entities, array $displays, $view_mode, $lang
       $bundle = $entity->bundle();
       $display = $displays[$bundle];
 
-      // The 'view' hook can be implemented to overwrite the default function
-      // to display nodes.
-      if (node_hook($bundle, 'view')) {
-        $entity = node_invoke($entity, 'view', $display, $view_mode, $langcode);
-      }
-
       $entity->content['links'] = array(
         '#theme' => 'links__node',
         '#pre_render' => array('drupal_pre_render_links'),
diff --git a/core/modules/node/lib/Drupal/node/NodeStorageController.php b/core/modules/node/lib/Drupal/node/NodeStorageController.php
index db3ba75..9455260 100644
--- a/core/modules/node/lib/Drupal/node/NodeStorageController.php
+++ b/core/modules/node/lib/Drupal/node/NodeStorageController.php
@@ -52,14 +52,6 @@ protected function attachLoad(&$queried_entities, $load_revision = FALSE) {
       field_attach_load($this->entityType, $queried_entities);
     }
 
-    // Call object type specific callbacks on each typed array of nodes.
-    foreach ($typed_nodes as $node_type => $nodes_of_type) {
-      // Retrieve the node type 'base' hook implementation based on a Node in
-      // the type-specific stack.
-      if ($function = node_hook($node_type, 'load')) {
-        $function($nodes_of_type);
-      }
-    }
     // Besides the list of nodes, pass one additional argument to
     // hook_node_load(), containing a list of node types that were loaded.
     $argument = array_keys($typed_nodes);
@@ -85,15 +77,6 @@ protected function attachLoad(&$queried_entities, $load_revision = FALSE) {
   protected function invokeHook($hook, EntityInterface $node) {
     $node = $node->getBCEntity();
 
-    if ($hook == 'insert' || $hook == 'update') {
-      node_invoke($node, $hook);
-    }
-    else if ($hook == 'predelete') {
-      // 'delete' is triggered in 'predelete' is here to preserve hook ordering
-      // from Drupal 7.
-      node_invoke($node, 'delete');
-    }
-
     // Inline parent::invokeHook() to pass on BC-entities to node-specific
     // hooks.
 
diff --git a/core/modules/node/node.api.php b/core/modules/node/node.api.php
index 8bd1d9a..48c5c3c 100644
--- a/core/modules/node/node.api.php
+++ b/core/modules/node/node.api.php
@@ -44,7 +44,6 @@
  *   - hook_node_presave() (all)
  *   - hook_entity_presave() (all)
  *   - Node and revision records are written to the database
- *   - hook_insert() (node-type-specific)
  *   - field_attach_insert()
  *   - hook_node_insert() (all)
  *   - hook_entity_insert() (all)
@@ -55,7 +54,6 @@
  *   - hook_node_presave() (all)
  *   - hook_entity_presave() (all)
  *   - Node and revision records are written to the database
- *   - hook_update() (node-type-specific)
  *   - field_attach_update()
  *   - hook_node_update() (all)
  *   - hook_entity_update() (all)
@@ -64,13 +62,11 @@
  * - Loading a node (calling node_load(), node_load_multiple(), entity_load(),
  *   or entity_load_multiple() with $entity_type of 'node'):
  *   - Node and revision information is read from database.
- *   - hook_load() (node-type-specific)
  *   - field_attach_load_revision() and field_attach_load()
  *   - hook_entity_load() (all)
  *   - hook_node_load() (all)
  * - Viewing a single node (calling node_view() - note that the input to
  *   node_view() is a loaded node, so the Loading steps above are already done):
- *   - hook_view() (node-type-specific)
  *   - field_attach_prepare_view()
  *   - hook_entity_prepare_view() (all)
  *   - field_attach_view()
@@ -83,7 +79,6 @@
  *   above are already done):
  *   - field_attach_prepare_view()
  *   - hook_entity_prepare_view() (all)
- *   - hook_view() (node-type-specific)
  *   - field_attach_view()
  *   - hook_node_view() (all)
  *   - hook_entity_view() (all)
@@ -91,7 +86,6 @@
  *   - hook_entity_view_alter() (all)
  * - Deleting a node (calling $node->delete() or entity_delete_multiple()):
  *   - Node is loaded (see Loading section above)
- *   - hook_delete() (node-type-specific)
  *   - hook_node_predelete() (all)
  *   - hook_entity_predelete() (all)
  *   - field_attach_delete()
@@ -105,13 +99,11 @@
  *   - field_attach_delete_revision()
  * - Preparing a node for editing (calling node_form() - note that if it is an
  *   existing node, it will already be loaded; see the Loading section above):
- *   - hook_prepare() (node-type-specific)
  *   - hook_node_prepare() (all)
  *   - hook_form() (node-type-specific)
  *   - field_attach_form()
  * - Validating a node during editing form submit (calling
  *   node_form_validate()):
- *   - hook_validate() (node-type-specific)
  *   - hook_node_validate() (all)
  *   - field_attach_form_validate()
  * - Searching (calling node_search_execute()):
@@ -984,7 +976,6 @@ function hook_ranking() {
   }
 }
 
-
 /**
  * Respond to node type creation.
  *
@@ -1029,281 +1020,5 @@ function hook_node_type_delete($info) {
 }
 
 /**
- * Respond to node deletion.
- *
- * This hook is invoked only on the module that defines the node's content type
- * (use hook_node_delete() to respond to all node deletions).
- *
- * This hook is invoked from entity_delete_multiple() after the node has been
- * removed from the node table in the database, before hook_node_delete() is
- * invoked, and before field_attach_delete() is called.
- *
- * @param \Drupal\Core\Entity\EntityInterface $node
- *   The node that is being deleted.
- *
- * @ingroup node_api_hooks
- */
-function hook_delete(\Drupal\Core\Entity\EntityInterface $node) {
-  db_delete('mytable')
-    ->condition('nid', $node->nid)
-    ->execute();
-}
-
-/**
- * Act on a node object about to be shown on the add/edit form.
- *
- * This hook is invoked only on the module that defines the node's content type
- * (use hook_node_prepare() to act on all node preparations).
- *
- * This hook is invoked from NodeFormController::prepareEntity() before the
- * general hook_node_prepare() is invoked.
- *
- * @param \Drupal\Core\Entity\EntityInterface $node
- *   The node that is about to be shown on the add/edit form.
- *
- * @ingroup node_api_hooks
- */
-function hook_prepare(\Drupal\Core\Entity\EntityInterface $node) {
-  if ($file = file_check_upload($field_name)) {
-    $file = file_save_upload($field_name, _image_filename($file->filename, NULL, TRUE), FALSE, 0);
-    if ($file) {
-      if (!image_get_info($file->uri)) {
-        form_set_error($field_name, t('Uploaded file is not a valid image'));
-        return;
-      }
-    }
-    else {
-      return;
-    }
-    $node->images['_original'] = $file->uri;
-    _image_build_derivatives($node, TRUE);
-    $node->new_file = TRUE;
-  }
-}
-
-/**
- * Display a node editing form.
- *
- * This hook, implemented by node modules, is called to retrieve the form
- * that is displayed to create or edit a node. This form is displayed at path
- * node/add/[node type] or node/[node ID]/edit.
- *
- * The submit and preview buttons, administrative and display controls, and
- * sections added by other modules (such as path settings, menu settings,
- * comment settings, and fields managed by the Field UI module) are
- * displayed automatically by the node module. This hook just needs to
- * return the node title and form editing fields specific to the node type.
- *
- * @param \Drupal\Core\Entity\EntityInterface $node
- *   The node being added or edited.
- * @param $form_state
- *   The form state array.
- *
- * @return
- *   An array containing the title and any custom form elements to be displayed
- *   in the node editing form.
- *
- * @ingroup node_api_hooks
- */
-function hook_form(\Drupal\Core\Entity\EntityInterface $node, &$form_state) {
-  $type = node_type_load($node->type);
-
-  $form['title'] = array(
-    '#type' => 'textfield',
-    '#title' => check_plain($type->title_label),
-    '#default_value' => !empty($node->title) ? $node->title : '',
-    '#required' => TRUE, '#weight' => -5
-  );
-
-  $form['field1'] = array(
-    '#type' => 'textfield',
-    '#title' => t('Custom field'),
-    '#default_value' => $node->field1,
-    '#maxlength' => 127,
-  );
-  $form['selectbox'] = array(
-    '#type' => 'select',
-    '#title' => t('Select box'),
-    '#default_value' => $node->selectbox,
-    '#options' => array(
-      1 => 'Option A',
-      2 => 'Option B',
-      3 => 'Option C',
-    ),
-    '#description' => t('Choose an option.'),
-  );
-
-  return $form;
-}
-
-/**
- * Respond to creation of a new node.
- *
- * This hook is invoked only on the module that defines the node's content type
- * (use hook_node_insert() to act on all node insertions).
- *
- * This hook is invoked from $node->save() after the node is inserted into the
- * node table in the database, before field_attach_insert() is called, and
- * before hook_node_insert() is invoked.
- *
- * @param \Drupal\Core\Entity\EntityInterface $node
- *   The node that is being created.
- *
- * @ingroup node_api_hooks
- */
-function hook_insert(\Drupal\Core\Entity\EntityInterface $node) {
-  db_insert('mytable')
-    ->fields(array(
-      'nid' => $node->nid,
-      'extra' => $node->extra,
-    ))
-    ->execute();
-}
-
-/**
- * Act on nodes being loaded from the database.
- *
- * This hook is invoked only on the module that defines the node's content type
- * (use hook_node_load() to respond to all node loads).
- *
- * This hook is invoked during node loading, which is handled by entity_load(),
- * via classes Drupal\node\NodeStorageController and
- * Drupal\Core\Entity\DatabaseStorageController. After the node information is
- * read from the database or the entity cache, hook_load() is invoked on the
- * node's content type module, then field_attach_node_revision() or
- * field_attach_load() is called, then hook_entity_load() is invoked on all
- * implementing modules, and finally hook_node_load() is invoked on all
- * implementing modules.
- *
- * This hook should only be used to add information that is not in the node or
- * node revisions table, not to replace information that is in these tables
- * (which could interfere with the entity cache). For performance reasons,
- * information for all available nodes should be loaded in a single query where
- * possible.
- *
- * @param $nodes
- *   An array of the nodes being loaded, keyed by nid.
- *
- * For a detailed usage example, see node_example.module.
- *
- * @ingroup node_api_hooks
- */
-function hook_load($nodes) {
-  $result = db_query('SELECT nid, foo FROM {mytable} WHERE nid IN (:nids)', array(':nids' => array_keys($nodes)));
-  foreach ($result as $record) {
-    $nodes[$record->nid]->foo = $record->foo;
-  }
-}
-
-/**
- * Respond to updates to a node.
- *
- * This hook is invoked only on the module that defines the node's content type
- * (use hook_node_update() to act on all node updates).
- *
- * This hook is invoked from $node->save() after the node is updated in the
- * node table in the database, before field_attach_update() is called, and
- * before hook_node_update() is invoked.
- *
- * @param \Drupal\Core\Entity\EntityInterface $node
- *   The node that is being updated.
- *
- * @ingroup node_api_hooks
- */
-function hook_update(\Drupal\Core\Entity\EntityInterface $node) {
-  db_update('mytable')
-    ->fields(array('extra' => $node->extra))
-    ->condition('nid', $node->nid)
-    ->execute();
-}
-
-/**
- * Perform node validation before a node is created or updated.
- *
- * This hook is invoked only on the module that defines the node's content type
- * (use hook_node_validate() to act on all node validations).
- *
- * This hook is invoked from NodeFormController::validate(), after a user has
- * finished editing the node and is previewing or submitting it. It is invoked
- * at the end of all the standard validation steps, and before
- * hook_node_validate() is invoked.
- *
- * To indicate a validation error, use form_set_error().
- *
- * Note: Changes made to the $node object within your hook implementation will
- * have no effect.  The preferred method to change a node's content is to use
- * hook_node_presave() instead.
- *
- * @param \Drupal\Core\Entity\EntityInterface $node
- *   The node being validated.
- * @param $form
- *   The form being used to edit the node.
- * @param $form_state
- *   The form state array.
- *
- * @ingroup node_api_hooks
- */
-function hook_validate(\Drupal\Core\Entity\EntityInterface $node, $form, &$form_state) {
-  if (isset($node->end) && isset($node->start)) {
-    if ($node->start > $node->end) {
-      form_set_error('time', t('An event may not end before it starts.'));
-    }
-  }
-}
-
-/**
- * Display a node.
- *
- * This hook is invoked only on the module that defines the node's content type
- * (use hook_node_view() to act on all node views).
- *
- * This hook is invoked during node viewing after the node is fully loaded, so
- * that the node type module can define a custom method for display, or add to
- * the default display.
- *
- * @param \Drupal\Core\Entity\EntityInterface $node
- *   The node to be displayed, as returned by node_load().
- * @param \Drupal\entity\Plugin\Core\Entity\EntityDisplay $display
- *   The entity_display object holding the display options configured for the
- *   node components.
- * @param $view_mode
- *   View mode, e.g. 'full', 'teaser', ...
- *
- * @return
- *   The passed $node parameter should be modified as necessary and returned so
- *   it can be properly presented. Nodes are prepared for display by assembling
- *   a structured array, formatted as in the Form API, in $node->content. As
- *   with Form API arrays, the #weight property can be used to control the
- *   relative positions of added elements. After this hook is invoked,
- *   node_view() calls field_attach_view() to add field views to $node->content,
- *   and then invokes hook_node_view() and hook_node_view_alter(), so if you
- *   want to affect the final view of the node, you might consider implementing
- *   one of these hooks instead.
- *
- * @ingroup node_api_hooks
- */
-function hook_view(\Drupal\Core\Entity\EntityInterface $node, \Drupal\entity\Plugin\Core\Entity\EntityDisplay $display, $view_mode) {
-  if ($view_mode == 'full' && node_is_page($node)) {
-    $breadcrumb = array();
-    $breadcrumb[] = l(t('Home'), NULL);
-    $breadcrumb[] = l(t('Example'), 'example');
-    $breadcrumb[] = l($node->field1, 'example/' . $node->field1);
-    drupal_set_breadcrumb($breadcrumb);
-  }
-
-  // Only do the extra work if the component is configured to be displayed.
-  // This assumes a 'mymodule_addition' extra field has been defined for the
-  // node type in hook_field_extra_fields().
-  if ($display->getComponent('mymodule_addition')) {
-    $node->content['mymodule_addition'] = array(
-      '#markup' => mymodule_addition($node),
-      '#theme' => 'mymodule_my_additional_field',
-    );
-  }
-
-  return $node;
-}
-
-/**
  * @} End of "addtogroup hooks".
  */
diff --git a/core/modules/node/node.module b/core/modules/node/node.module
index ef9fd7f..c5827d0 100644
--- a/core/modules/node/node.module
+++ b/core/modules/node/node.module
@@ -329,8 +329,6 @@ function node_type_get_types() {
  *
  * @return string|false
  *   The node type base or FALSE if the node type is not found.
- *
- * @see node_invoke()
  */
 function node_type_get_base($type) {
   $types = _node_types_build()->types;
@@ -856,42 +854,6 @@ function node_rdf_mapping() {
 }
 
 /**
- * Determines whether a node hook exists.
- *
- * @param string $type
- *   A string containing the node type.
- * @param $hook
- *   A string containing the name of the hook.
- *
- * @return string|false
- *   A string containing the function name or FALSE if it isn't found.
- */
-function node_hook($type, $hook) {
-  $base = node_type_get_base($type);
-  return module_hook($base, $hook) ? $base . '_' . $hook : FALSE;
-}
-
-/**
- * Invokes a node hook.
- *
- * @param \Drupal\Core\Entity\EntityInterface $node
- *   A Node entity.
- * @param $hook
- *   A string containing the name of the hook.
- * @param $a2, $a3, $a4
- *   (optional) Arguments to pass on to the hook, after the $node argument. All
- *   default to NULL.
- *
- * @return
- *   The returned value of the invoked hook.
- */
-function node_invoke(EntityInterface $node, $hook, $a2 = NULL, $a3 = NULL, $a4 = NULL) {
-  if ($function = node_hook($node->type, $hook)) {
-    return $function($node, $a2, $a3, $a4);
-  }
-}
-
-/**
  * Loads node entities from the database.
  *
  * This function should be used whenever you need to load more than one node
@@ -1575,7 +1537,7 @@ function _node_revision_access(EntityInterface $node, $op = 'view', $account = N
 function _node_add_access() {
   $types = node_type_get_types();
   foreach ($types as $type) {
-    if (node_hook($type->type, 'form') && node_access('create', $type->type)) {
+    if (node_access('create', $type->type)) {
       return TRUE;
     }
   }
@@ -3119,29 +3081,6 @@ function _node_access_rebuild_batch_finished($success, $results, $operations) {
  */
 
 /**
- * Implements hook_form().
- */
-function node_content_form(EntityInterface $node, $form_state) {
-  // @todo It is impossible to define a content type without implementing
-  //   hook_form(). Remove this requirement.
-  $form = array();
-  $type = node_type_load($node->type);
-
-  if ($type->has_title) {
-    $form['title'] = array(
-      '#type' => 'textfield',
-      '#title' => check_plain($type->title_label),
-      '#required' => TRUE,
-      '#default_value' => $node->title,
-      '#maxlength' => 255,
-      '#weight' => -5,
-    );
-  }
-
-  return $form;
-}
-
-/**
  * @} End of "defgroup node_content".
  */
 
diff --git a/core/modules/node/node.pages.inc b/core/modules/node/node.pages.inc
index 8255df5..9830e1f 100644
--- a/core/modules/node/node.pages.inc
+++ b/core/modules/node/node.pages.inc
@@ -27,7 +27,7 @@ function node_add_page() {
   $content = array();
   // Only use node types the user has access to.
   foreach (node_type_get_types() as $type) {
-    if (node_hook($type->type, 'form') && node_access('create', $type->type)) {
+    if (node_access('create', $type->type)) {
       $content[$type->type] = $type;
     }
   }
@@ -92,9 +92,7 @@ function node_add($node_type) {
     'langcode' => $langcode ? $langcode : language_default()->langcode,
   ))->getBCEntity();
   drupal_set_title(t('Create @name', array('@name' => $node_type->name)), PASS_THROUGH);
-  $output = entity_get_form($node);
-
-  return $output;
+  return entity_get_form($node);
 }
 
 /**
