diff --git a/flag.info b/flag.info
index 6933238..c00bb13 100644
--- a/flag.info
+++ b/flag.info
@@ -8,6 +8,7 @@ configure = admin/structure/flags
 files[] = flag.inc
 files[] = flag.rules.inc
 files[] = includes/flag_handler_argument_content_id.inc
+files[] = includes/flag_handler_field_entity_ops.inc
 files[] = includes/flag_handler_field_ops.inc
 files[] = includes/flag_handler_filter_flagged.inc
 files[] = includes/flag_handler_relationships.inc
diff --git a/includes/flag.views.inc b/includes/flag.views.inc
index 3dd6df0..346a8c2 100644
--- a/includes/flag.views.inc
+++ b/includes/flag.views.inc
@@ -26,6 +26,9 @@ function flag_views_handlers() {
         'parent' => 'views_handler_relationship',
         'file' => 'flag_handler_relationships.inc',
       ),
+      'flag_handler_field_entity_ops' => array(
+        'parent' => 'views_handler_field_entity',
+      ),
       'flag_handler_field_ops' => array(
         'parent' => 'views_handler_field',
       ),
@@ -120,6 +123,15 @@ function flag_views_data() {
     ),
   );
 
+  // Flag entity links.
+  $data['views_entity_node']['flag_ops_entity'] = array(
+      'title' => t('Flag link for entities'),
+      'help' => t('Display flag/unflag link.'),
+      'field' => array(
+          'handler' => 'flag_handler_field_entity_ops',
+      ),
+  );
+
   // Flag content links.
   $data['flag_content']['ops'] = array(
     'title' => t('Flag link'),
diff --git a/includes/flag_handler_field_entity_ops.inc b/includes/flag_handler_field_entity_ops.inc
new file mode 100644
index 0000000..b36a2f1
--- /dev/null
+++ b/includes/flag_handler_field_entity_ops.inc
@@ -0,0 +1,117 @@
+<?php
+
+/**
+ * @file
+ * Contains the flag Ops field handler for generic entities.
+ */
+
+/**
+ * Views field handler for the Flag operations links (flag/unflag) for entities.
+ *
+ * @ingroup views
+ */
+class flag_handler_field_entity_ops extends views_handler_field_entity {
+
+  /**
+   * Returns the flag object associated with our field.
+   *
+   * A field is in some relationship. This function reaches out for this
+   * relationship and reads its 'flag' option, which holds the flag name.
+   */
+  function get_flag() {
+    return flag_get_flag($this->options['flag']);
+  }
+
+  function option_definition() {
+    $options = parent::option_definition();
+    $options['link_type'] = array('default' => '');
+    $options['flag'] = array('default' => NULL);
+    return $options;
+  }
+
+  function options_form(&$form, &$form_state) {
+    parent::options_form($form, $form_state);
+
+    $form['link_type'] = array(
+      '#type' => 'radios',
+      '#title' => t('Link type'),
+      '#options' => array('' => t('Use flag link settings')) + _flag_link_type_options(),
+      '#default_value' => $this->options['link_type'],
+    );
+
+    //@todo: same code in flag_handler_relationship_content
+    $form['flag'] = flag_views_flag_config_form('radios', $content_type, $this->options['flag']);
+    if (!$form['flag']['#options']) {
+      $form = array(
+        'error' => array(
+          '#markup' => '<p class="error form-item">' . t('No %type flags exist. You must first <a href="@create-url">create a %type flag</a> before being able to use this field.', array('%type' => $content_type, '@create-url' => url(FLAG_ADMIN_PATH))) . '</p>',
+        ),
+      );
+      $form_state['no flags exist'] = TRUE;
+    }
+  }
+
+/**
+   * @todo: same code in flag_handler_relationship->validate()
+   *
+   * Make sure the flag exists.
+   *
+   * When importing views, or when deleting flags, inconsistent views may
+   * result. This validator is called by Views before saving or previewing a
+   * view.
+   */
+  function validate() {
+    $errors = array();
+    $tokens = array(
+      '@field-name' => $this->definition['title'],
+      '@flag-name' => $this->options['flag'],
+    );
+    if (!$this->options['flag']) {
+      $errors[] = t('You must pick a flag to use for the field "@field-name".', $tokens);
+    }
+    elseif (!flag_get_flag($this->options['flag'])) {
+      $errors[] = t('This view is looking for a flag by the name "@flag-name", but there is no such flag. Perhaps it was deleted. Please update the field "@field-name" in this view to use an existing flag.', $tokens);
+    }
+    return $errors;
+  }
+
+  /**
+   * Find out if the flag applies to each item seen on the page. It's done in a
+   * separate DB query to to avoid complexity and to make 'many to one' tests
+   * (e.g. checking user roles) possible without causing duplicate rows.
+   */
+  function pre_render(&$values) {
+    if (!($flag = $this->get_flag())) {
+      // Error message is printed in render().
+      return;
+    }
+
+    $ids = array();
+    foreach ($values as $item) {
+      $is_flagged = $flag->is_flagged($item->entity);
+      $ids[$item->entity] = $is_flagged ? 'unflag' : 'flag';
+    }
+    $this->ids = $ids;
+    $this->flag_applies = $ids ? $flag->access_multiple($ids) : array();
+  }
+
+  function render($values) {
+    if (!($flag = $this->get_flag())) {
+      // get_flag() itself will print a more detailed message.
+      return t('Missing flag');
+    }
+
+    $id = $values->entity;
+    $flag_value = $this->ids[$id];
+
+    if (empty($this->flag_applies[$id])) {
+      // Flag does not apply to this content.
+      return;
+    }
+
+    if (!empty($this->options['link_type'])) {
+      $flag->link_type = $this->options['link_type'];
+    }
+    return $flag->theme($flag_value, $id);
+  }
+}
