Index: includes/common.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/common.inc,v
retrieving revision 1.1210
diff -u -p -r1.1210 common.inc
--- includes/common.inc	22 Aug 2010 12:46:21 -0000	1.1210
+++ includes/common.inc	26 Aug 2010 14:46:49 -0000
@@ -6718,6 +6718,31 @@ function entity_uri($entity_type, $entit
 }
 
 /**
+ * Returns the label of an entity.
+ *
+ * @param $entity_type
+ *   The entity type; e.g. 'node' or 'user'.
+ * @param $entity
+ *   The entity for which to generate a path.
+ *
+ * @return
+ *   A string with the entity label (e.g. node title), or FALSE if not found.
+ */
+function entity_label($entity_type, $entity) {
+  $label = FALSE;
+  $info = entity_get_info($entity_type);
+  if (isset($info['label callback']) && function_exists($info['label callback'])) {
+    $label = $info['label callback']($entity);
+  }
+  elseif (!empty($info['entity keys']['label']) && isset($entity->{$info['entity keys']['label']})) {
+    $label = $entity->{$info['entity keys']['label']};
+  }
+
+  return $label;
+}
+
+
+/**
  * Helper function for attaching field API validation to entity forms.
  */
 function entity_form_field_validate($entity_type, $form, &$form_state) {
Index: modules/comment/comment.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/comment/comment.module,v
retrieving revision 1.892
diff -u -p -r1.892 comment.module
--- modules/comment/comment.module	23 Aug 2010 14:53:50 -0000	1.892
+++ modules/comment/comment.module	26 Aug 2010 14:46:50 -0000
@@ -103,6 +103,7 @@ function comment_entity_info() {
       'entity keys' => array(
         'id' => 'cid',
         'bundle' => 'node_type',
+        'label' => 'subject',
       ),
       'bundles' => array(),
       'view modes' => array(
Index: modules/field/tests/field.test
===================================================================
RCS file: /cvs/drupal/drupal/modules/field/tests/field.test,v
retrieving revision 1.39
diff -u -p -r1.39 field.test
--- modules/field/tests/field.test	18 Aug 2010 00:44:52 -0000	1.39
+++ modules/field/tests/field.test	26 Aug 2010 14:46:50 -0000
@@ -2988,3 +2988,52 @@ class FieldBulkDeleteTestCase extends Fi
     $this->assertEqual(count($fields), 0, 'The field is purged.');
   }
 }
+
+
+/**
+ * Test properties of entity.
+ */
+class EntityProperties extends FieldTestCase {
+  public static function getInfo() {
+    return array(
+      'name' => 'Entity tests',
+      'description'=> 'Test entity functionality.',
+      'group' => 'System',
+    );
+  }
+
+  function setUp() {
+    parent::setUp('field_test');
+  }
+
+  /**
+  * Test label key and label callback of an entity.
+  */
+  function testEntityLabel() {
+    $entity_types = array(
+      'test_entity_no_label',
+      'test_entity_label',
+      'test_entity_label_callback',
+    );
+
+    $entity = field_test_create_stub_entity();
+
+    foreach ($entity_types as $entity_type) {
+      $label = entity_label($entity_type, $entity);
+
+      switch ($entity_type) {
+        case 'test_entity_no_label':
+          $this->assertFalse($label, 'Entity with no label property or callback returned FALSE.');
+          break;
+
+        case 'test_entity_label':
+          $this->assertEqual($label, $entity->ftlabel, 'Entity with label key returned correct label.');
+          break;
+
+        case 'test_entity_label_callback':
+          $this->assertEqual($label, 'label callback ' . $entity->ftlabel, 'Entity with label callback returned correct label.');
+          break;
+      }
+    }
+  }
+}
Index: modules/field/tests/field_test.entity.inc
===================================================================
RCS file: /cvs/drupal/drupal/modules/field/tests/field_test.entity.inc,v
retrieving revision 1.12
diff -u -p -r1.12 field_test.entity.inc
--- modules/field/tests/field_test.entity.inc	17 Jun 2010 13:44:45 -0000	1.12
+++ modules/field/tests/field_test.entity.inc	26 Aug 2010 14:46:50 -0000
@@ -73,6 +73,50 @@ function field_test_entity_info() {
       'bundles' => array('test_entity_2' => array('label' => 'Test entity 2')),
       'view modes' => $test_entity_modes,
     ),
+
+    'test_entity_no_label' => array(
+      'name' => t('Test entity without label'),
+      'fieldable' => TRUE,
+      'field cache' => FALSE,
+      'base table' => 'test_entity',
+      'entity keys' => array(
+        'id' => 'ftid',
+        'revision' => 'ftvid',
+        'bundle' => 'fttype',
+      ),
+      'bundles' => $bundles,
+      'view modes' => $test_entity_modes,
+    ),
+    'test_entity_label' => array(
+      'name' => t('Test entity label'),
+      'fieldable' => TRUE,
+      'field cache' => FALSE,
+      'base table' => 'test_entity',
+      'entity keys' => array(
+        'id' => 'ftid',
+        'revision' => 'ftvid',
+        'bundle' => 'fttype',
+        'label' => 'ftlabel',
+      ),
+      'bundles' => $bundles,
+      'view modes' => $test_entity_modes,
+    ),
+    'test_entity_label_callback' => array(
+      'name' => t('Test entity label callback'),
+      'fieldable' => TRUE,
+      'field cache' => FALSE,
+      'base table' => 'test_entity',
+      'label callback' => 'field_test_entity_label_callback',
+      'entity keys' => array(
+        'id' => 'ftid',
+        'revision' => 'ftvid',
+        'bundle' => 'fttype',
+      ),
+      'bundles' => $bundles,
+      'view modes' => $test_entity_modes,
+    ),
+
+
   );
 }
 
@@ -163,7 +207,7 @@ function field_test_delete_bundle($bundle) {
 /**
  * Creates a basic test_entity entity.
  */
-function field_test_create_stub_entity($id = 1, $vid = 1, $bundle = 'test_bundle') {
+function field_test_create_stub_entity($id = 1, $vid = 1, $bundle = 'test_bundle', $label = '') {
   $entity = new stdClass();
   // Only set id and vid properties if they don't come as NULL (creation form).
   if (isset($id)) {
@@ -174,6 +218,9 @@ function field_test_create_stub_entity($
   }
   $entity->fttype = $bundle;
 
+  $label = !empty($label) ? $label : $bundle . ' label';
+  $entity->ftlabel = $label;
+
   return $entity;
 }
 
Index: modules/field/tests/field_test.install
===================================================================
RCS file: /cvs/drupal/drupal/modules/field/tests/field_test.install,v
retrieving revision 1.3
diff -u -p -r1.3 field_test.install
--- modules/field/tests/field_test.install	14 Jun 2010 15:41:02 -0000	1.3
+++ modules/field/tests/field_test.install	26 Aug 2010 14:46:50 -0000
@@ -44,6 +44,13 @@ function field_test_schema() {
         'not null' => TRUE,
         'default' => '',
       ),
+      'ftlabel' => array(
+        'description' => 'The label of this test_entity.',
+        'type' => 'varchar',
+        'length' => 255,
+        'not null' => TRUE,
+        'default' => '',
+      ),
     ),
     'unique keys' => array(
       'ftvid' => array('ftvid'),
Index: modules/field/tests/field_test.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/field/tests/field_test.module,v
retrieving revision 1.9
diff -u -p -r1.9 field_test.module
--- modules/field/tests/field_test.module	8 Aug 2010 02:18:53 -0000	1.9
+++ modules/field/tests/field_test.module	26 Aug 2010 14:46:50 -0000
@@ -214,3 +214,16 @@ function field_test_dummy_field_storage_
     ),
   );
 }
+
+/**
+ * Entity label callback.
+ *
+ * @param $entity
+ *   The entity object.
+ *
+ * @return
+ *   The label of the entity prefixed with "label callback".
+ */
+function field_test_entity_label_callback($entity) {
+  return 'label callback ' . $entity->ftlabel;
+}
\ No newline at end of file
Index: modules/node/node.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/node/node.module,v
retrieving revision 1.1293
diff -u -p -r1.1293 node.module
--- modules/node/node.module	23 Aug 2010 22:15:34 -0000	1.1293
+++ modules/node/node.module	26 Aug 2010 14:46:50 -0000
@@ -181,6 +181,7 @@ function node_entity_info() {
         'id' => 'nid',
         'revision' => 'vid',
         'bundle' => 'type',
+        'label' => 'title',
       ),
       'bundle keys' => array(
         'bundle' => 'type',
Index: modules/system/system.api.php
===================================================================
RCS file: /cvs/drupal/drupal/modules/system/system.api.php,v
retrieving revision 1.187
diff -u -p -r1.187 system.api.php
--- modules/system/system.api.php	22 Aug 2010 13:55:53 -0000	1.187
+++ modules/system/system.api.php	26 Aug 2010 14:46:51 -0000
@@ -87,6 +87,11 @@ function hook_hook_info_alter(&$hooks) {
  *   - uri callback: A function taking an entity as argument and returning the
  *     uri elements of the entity, e.g. 'path' and 'options'. The actual entity
  *     uri can be constructed by passing these elements to url().
+ *   - label callback: Optional; A function taking an entity as argument and
+ *     returning the label of the entity, e.g. the title of a node, or the
+ *     subject of a comment. This property can be used when the label is a
+ *     result of complex logic, otherwise the "label" property under
+ *     the "entity keys" array, should be used.
  *   - fieldable: Set to TRUE if you want your entity type to be fieldable.
  *   - entity keys: An array describing how the Field API can extract the
  *     information it needs from the objects of the type. Elements:
@@ -103,6 +108,11 @@ function hook_hook_info_alter(&$hooks) {
  *       omitted if this entity type exposes a single bundle (all entities have
  *       the same collection of fields). The name of this single bundle will be
  *       the same as the entity type.
+ *     - label: The name of the property that contains the entity label. For
+ *       example, the value of this property in the node entity will be 'title'.
+ *       Note that it is possible that an entity label is a result of more
+ *       complex logic, in such a case the "label callback" should be used.
+ *       see entity_label().
  *   - bundle keys: An array describing how the Field API can extract the
  *     information it needs from the bundle objects for this type (e.g
  *     $vocabulary objects for terms; not applicable for nodes). This entry can
Index: modules/system/system.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/system/system.module,v
retrieving revision 1.957
diff -u -p -r1.957 system.module
--- modules/system/system.module	22 Aug 2010 13:52:58 -0000	1.957
+++ modules/system/system.module	26 Aug 2010 14:46:51 -0000
@@ -264,6 +264,7 @@ function system_entity_info() {
       'base table' => 'file_managed',
       'entity keys' => array(
         'id' => 'fid',
+        'label' => 'filename',
       ),
       'static cache' => FALSE,
     ),
Index: modules/taxonomy/taxonomy.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/taxonomy/taxonomy.module,v
retrieving revision 1.603
diff -u -p -r1.603 taxonomy.module
--- modules/taxonomy/taxonomy.module	22 Aug 2010 15:45:03 -0000	1.603
+++ modules/taxonomy/taxonomy.module	26 Aug 2010 14:46:51 -0000
@@ -100,6 +100,7 @@ function taxonomy_entity_info() {
       'entity keys' => array(
         'id' => 'tid',
         'bundle' => 'vocabulary_machine_name',
+        'label' => 'name',
       ),
       'bundle keys' => array(
         'bundle' => 'machine_name',
@@ -131,6 +132,7 @@ function taxonomy_entity_info() {
     'base table' => 'taxonomy_vocabulary',
     'entity keys' => array(
       'id' => 'vid',
+      'label' => 'name',
     ),
     'fieldable' => FALSE,
   );
Index: modules/user/user.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/user/user.module,v
retrieving revision 1.1196
diff -u -p -r1.1196 user.module
--- modules/user/user.module	26 Aug 2010 09:14:33 -0000	1.1196
+++ modules/user/user.module	26 Aug 2010 14:46:51 -0000
@@ -146,6 +146,7 @@ function user_entity_info() {
       'controller class' => 'UserController',
       'base table' => 'users',
       'uri callback' => 'user_uri',
+      'label callback' => 'user_label',
       'fieldable' => TRUE,
       'entity keys' => array(
         'id' => 'uid',
@@ -180,6 +181,20 @@ function user_uri($user) {
 }
 
 /**
+ * Entity label callback.
+ *
+ * @param $account
+ *   The user object.
+ * @return
+ *   The user name, using format_username().
+ *
+ * @see entity_label()
+ */
+function user_label($account) {
+  return format_username($account);
+}
+
+/**
  * Implements hook_field_extra_fields().
  */
 function user_field_extra_fields() {
