diff --git a/chrome/browser/extensions/extension_context_menu_api.cc b/chrome/browser/extensions/extension_context_menu_api.cc
index 51e9dfb60b46cba07fb0d376f355abf3a926b2bc..a004b9784aa4e50560ea12993bc21c86221d54ed 100644
--- a/chrome/browser/extensions/extension_context_menu_api.cc
+++ b/chrome/browser/extensions/extension_context_menu_api.cc
@@ -174,22 +174,21 @@ bool ExtensionContextMenuFunction::SetURLPatterns(
   return true;
 }
 
-
 bool ExtensionContextMenuFunction::GetParent(
     const DictionaryValue& properties,
     const ExtensionMenuManager& manager,
     ExtensionMenuItem** result) {
   if (!properties.HasKey(kParentIdKey))
     return true;
-  ExtensionMenuItem::Id parent_id(extension_id(), 0);
+  ExtensionMenuItem::Id parent_id(profile(), extension_id(), 0);
   if (properties.HasKey(kParentIdKey) &&
-      !properties.GetInteger(kParentIdKey, &parent_id.second))
+      !properties.GetInteger(kParentIdKey, &parent_id.uid))
     return false;
 
   ExtensionMenuItem* parent = manager.GetItemById(parent_id);
   if (!parent) {
     error_ = "Cannot find menu item with id " +
-        base::IntToString(parent_id.second);
+        base::IntToString(parent_id.uid);
     return false;
   }
   if (parent->type() != ExtensionMenuItem::NORMAL) {
@@ -205,9 +204,9 @@ bool CreateContextMenuFunction::RunImpl() {
   EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(0, &properties));
   EXTENSION_FUNCTION_VALIDATE(properties != NULL);
 
-  ExtensionMenuItem::Id id(extension_id(), 0);
+  ExtensionMenuItem::Id id(profile(), extension_id(), 0);
   EXTENSION_FUNCTION_VALIDATE(properties->GetInteger(kGeneratedIdKey,
-                                                     &id.second));
+                                                     &id.uid));
   std::string title;
   if (properties->HasKey(kTitleKey) &&
       !properties->GetString(kTitleKey, &title))
@@ -241,13 +240,13 @@ bool CreateContextMenuFunction::RunImpl() {
 
   bool success = true;
   if (properties->HasKey(kParentIdKey)) {
-    ExtensionMenuItem::Id parent_id(extension_id(), 0);
+    ExtensionMenuItem::Id parent_id(profile(), extension_id(), 0);
     EXTENSION_FUNCTION_VALIDATE(properties->GetInteger(kParentIdKey,
-                                                       &parent_id.second));
+                                                       &parent_id.uid));
     ExtensionMenuItem* parent = menu_manager->GetItemById(parent_id);
     if (!parent) {
       error_ = ExtensionErrorUtils::FormatErrorMessage(
-          kCannotFindItemError, base::IntToString(parent_id.second));
+          kCannotFindItemError, base::IntToString(parent_id.uid));
       return false;
     }
     if (parent->type() != ExtensionMenuItem::NORMAL) {
@@ -266,15 +265,15 @@ bool CreateContextMenuFunction::RunImpl() {
 }
 
 bool UpdateContextMenuFunction::RunImpl() {
-  ExtensionMenuItem::Id item_id(extension_id(), 0);
-  EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &item_id.second));
+  ExtensionMenuItem::Id item_id(profile(), extension_id(), 0);
+  EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &item_id.uid));
 
   ExtensionsService* service = profile()->GetExtensionsService();
   ExtensionMenuManager* manager = service->menu_manager();
   ExtensionMenuItem* item = manager->GetItemById(item_id);
   if (!item || item->extension_id() != extension_id()) {
     error_ = ExtensionErrorUtils::FormatErrorMessage(
-        kCannotFindItemError, base::IntToString(item_id.second));
+        kCannotFindItemError, base::IntToString(item_id.uid));
     return false;
   }
 
@@ -333,8 +332,8 @@ bool UpdateContextMenuFunction::RunImpl() {
 }
 
 bool RemoveContextMenuFunction::RunImpl() {
-  ExtensionMenuItem::Id id(extension_id(), 0);
-  EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &id.second));
+  ExtensionMenuItem::Id id(profile(), extension_id(), 0);
+  EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &id.uid));
   ExtensionsService* service = profile()->GetExtensionsService();
   ExtensionMenuManager* manager = service->menu_manager();
 
@@ -342,7 +341,7 @@ bool RemoveContextMenuFunction::RunImpl() {
   // Ensure one extension can't remove another's menu items.
   if (!item || item->extension_id() != extension_id()) {
     error_ = ExtensionErrorUtils::FormatErrorMessage(
-        kCannotFindItemError, base::IntToString(id.second));
+        kCannotFindItemError, base::IntToString(id.uid));
     return false;
   }
 
diff --git a/chrome/browser/extensions/extension_context_menu_browsertest.cc b/chrome/browser/extensions/extension_context_menu_browsertest.cc
index b0041ad27522b580710bd2812b4b5a30c063945b..73f4acf5d433af1f442e0c47ee5f7fe00a3eff96 100644
--- a/chrome/browser/extensions/extension_context_menu_browsertest.cc
+++ b/chrome/browser/extensions/extension_context_menu_browsertest.cc
@@ -5,6 +5,7 @@
 #include "app/menus/menu_model.h"
 #include "chrome/app/chrome_dll_resource.h"
 #include "chrome/browser/browser.h"
+#include "chrome/browser/browser_list.h"
 #include "chrome/browser/extensions/extension_browsertest.h"
 #include "chrome/browser/extensions/extension_test_message_listener.h"
 #include "chrome/browser/extensions/extensions_service.h"
@@ -122,9 +123,16 @@ class ExtensionContextMenuBrowserTest : public ExtensionBrowserTest {
     return LoadExtension(extension_dir);
   }
 
-  TestRenderViewContextMenu* CreateMenu(const GURL& page_url,
+  bool LoadContextMenuExtensionIncognito(std::string subdirectory) {
+    FilePath extension_dir =
+        test_data_dir_.AppendASCII("context_menus").AppendASCII(subdirectory);
+    return LoadExtensionIncognito(extension_dir);
+  }
+
+  TestRenderViewContextMenu* CreateMenu(Browser* browser,
+                                        const GURL& page_url,
                                         const GURL& link_url) {
-    TabContents* tab_contents = browser()->GetSelectedTabContents();
+    TabContents* tab_contents = browser->GetSelectedTabContents();
     WebContextMenuData data;
     ContextMenuParams params(data);
     params.page_url = page_url;
@@ -173,7 +181,8 @@ class ExtensionContextMenuBrowserTest : public ExtensionBrowserTest {
   bool MenuHasItemWithLabel(const GURL& page_url,
                             const GURL& link_url,
                             const std::string& label) {
-    scoped_ptr<TestRenderViewContextMenu> menu(CreateMenu(page_url, link_url));
+    scoped_ptr<TestRenderViewContextMenu> menu(
+        CreateMenu(browser(), page_url, link_url));
     return menu->HasExtensionItemWithLabel(label);
   }
 };
@@ -190,7 +199,8 @@ IN_PROC_BROWSER_TEST_F(ExtensionContextMenuBrowserTest, Simple) {
   GURL page_url("http://www.google.com");
 
   // Create and build our test context menu.
-  scoped_ptr<TestRenderViewContextMenu> menu(CreateMenu(page_url, GURL()));
+  scoped_ptr<TestRenderViewContextMenu> menu(
+      CreateMenu(browser(), page_url, GURL()));
 
   // Look for the extension item in the menu, and execute it.
   int command_id = IDC_EXTENSIONS_CONTEXT_CUSTOM_FIRST;
@@ -249,7 +259,8 @@ IN_PROC_BROWSER_TEST_F(ExtensionContextMenuBrowserTest, LongTitle) {
   // Create a context menu, then find the item's label. It should be properly
   // truncated.
   GURL url("http://foo.com/");
-  scoped_ptr<TestRenderViewContextMenu> menu(CreateMenu(url, GURL()));
+  scoped_ptr<TestRenderViewContextMenu> menu(
+      CreateMenu(browser(), url, GURL()));
 
   string16 label;
   ASSERT_TRUE(menu->GetItemLabel(item->id(), &label));
@@ -313,7 +324,8 @@ IN_PROC_BROWSER_TEST_F(ExtensionContextMenuBrowserTest, Separators) {
   listener1.WaitUntilSatisfied();
 
   GURL url("http://www.google.com/");
-  scoped_ptr<TestRenderViewContextMenu> menu(CreateMenu(url, GURL()));
+  scoped_ptr<TestRenderViewContextMenu> menu(
+      CreateMenu(browser(), url, GURL()));
 
   // The top-level item should be an "automagic parent" with the extension's
   // name.
@@ -336,7 +348,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionContextMenuBrowserTest, Separators) {
   ui_test_utils::NavigateToURL(browser(),
                                GURL(extension->GetResourceURL("test2.html")));
   listener2.WaitUntilSatisfied();
-  menu.reset(CreateMenu(url, GURL()));
+  menu.reset(CreateMenu(browser(), url, GURL()));
   ASSERT_TRUE(menu->GetMenuModelAndItemIndex(
       IDC_EXTENSIONS_CONTEXT_CUSTOM_FIRST, &model, &index));
   EXPECT_EQ(UTF8ToUTF16("parent"), model->GetLabelAt(index));
@@ -368,3 +380,50 @@ IN_PROC_BROWSER_TEST_F(ExtensionContextMenuBrowserTest, TargetURLs) {
                                     non_google_url,
                                     std::string("item1")));
 }
+
+// Tests adding a simple context menu item.
+IN_PROC_BROWSER_TEST_F(ExtensionContextMenuBrowserTest, IncognitoSplit) {
+  ExtensionTestMessageListener created("created item regular", false);
+  ExtensionTestMessageListener created_incognito("created item incognito",
+                                                 false);
+
+  ExtensionTestMessageListener onclick("onclick fired regular", false);
+  ExtensionTestMessageListener onclick_incognito("onclick fired incognito",
+                                                 false);
+
+  // Open an incognito window.
+  ui_test_utils::OpenURLOffTheRecord(browser()->profile(), GURL("about:blank"));
+
+  ASSERT_TRUE(LoadContextMenuExtensionIncognito("incognito"));
+
+  // Wait for the extension's processes to tell us they've created an item.
+  ASSERT_TRUE(created.WaitUntilSatisfied());
+  ASSERT_TRUE(created_incognito.WaitUntilSatisfied());
+
+  GURL page_url("http://www.google.com");
+
+  // Create and build our test context menu.
+  Browser* browser_incognito = BrowserList::FindBrowserWithType(
+      browser()->profile()->GetOffTheRecordProfile(),
+      Browser::TYPE_NORMAL, false);
+  ASSERT_TRUE(browser_incognito);
+  scoped_ptr<TestRenderViewContextMenu> menu(
+      CreateMenu(browser(), page_url, GURL()));
+  scoped_ptr<TestRenderViewContextMenu> menu_incognito(
+      CreateMenu(browser_incognito, page_url, GURL()));
+
+  // Look for the extension item in the menu, and execute it.
+  int command_id = IDC_EXTENSIONS_CONTEXT_CUSTOM_FIRST;
+  ASSERT_TRUE(menu->IsCommandIdEnabled(command_id));
+  menu->ExecuteCommand(command_id);
+
+  // Wait for the extension's script to tell us its onclick fired. Ensure
+  // that the incognito version doesn't fire until we explicitly click the
+  // incognito menu item.
+  ASSERT_TRUE(onclick.WaitUntilSatisfied());
+  EXPECT_FALSE(onclick_incognito.was_satisfied());
+
+  ASSERT_TRUE(menu_incognito->IsCommandIdEnabled(command_id));
+  menu_incognito->ExecuteCommand(command_id);
+  ASSERT_TRUE(onclick_incognito.WaitUntilSatisfied());
+}
diff --git a/chrome/browser/extensions/extension_event_router.cc b/chrome/browser/extensions/extension_event_router.cc
index b1577167774aecacdb6a025791075effdea66302..c03345445ff104262a492037cc24d6a2e13f5db8 100644
--- a/chrome/browser/extensions/extension_event_router.cc
+++ b/chrome/browser/extensions/extension_event_router.cc
@@ -33,17 +33,6 @@ static void DispatchEvent(RenderProcessHost* renderer,
       extension_id, kDispatchEvent, args, event_url));
 }
 
-static bool CanCrossIncognito(Profile* profile,
-                              const std::string& extension_id) {
-  // We allow the extension to see events and data from another profile iff it
-  // uses "spanning" behavior and it has incognito access. "split" mode
-  // extensions only see events for a matching profile.
-  const Extension* extension =
-      profile->GetExtensionsService()->GetExtensionById(extension_id, false);
-  return (profile->GetExtensionsService()->IsIncognitoEnabled(extension) &&
-          !extension->incognito_split_mode());
-}
-
 }  // namespace
 
 struct ExtensionEventRouter::EventListener {
@@ -63,6 +52,24 @@ struct ExtensionEventRouter::EventListener {
   }
 };
 
+// static
+bool ExtensionEventRouter::CanCrossIncognito(Profile* profile,
+                                             const std::string& extension_id) {
+  const Extension* extension =
+      profile->GetExtensionsService()->GetExtensionById(extension_id, false);
+  return CanCrossIncognito(profile, extension);
+}
+
+// static
+bool ExtensionEventRouter::CanCrossIncognito(Profile* profile,
+                                             const Extension* extension) {
+  // We allow the extension to see events and data from another profile iff it
+  // uses "spanning" behavior and it has incognito access. "split" mode
+  // extensions only see events for a matching profile.
+  return (profile->GetExtensionsService()->IsIncognitoEnabled(extension) &&
+          !extension->incognito_split_mode());
+}
+
 ExtensionEventRouter::ExtensionEventRouter(Profile* profile)
     : profile_(profile),
       extension_devtools_manager_(profile->GetExtensionDevToolsManager()) {
diff --git a/chrome/browser/extensions/extension_event_router.h b/chrome/browser/extensions/extension_event_router.h
index 5e1ca970052c88b878455c9452cde2362ce1c411..c9f1f21e204c9abb3cef53a40b90c4b5f7d19fb4 100644
--- a/chrome/browser/extensions/extension_event_router.h
+++ b/chrome/browser/extensions/extension_event_router.h
@@ -15,12 +15,19 @@
 #include "chrome/common/notification_registrar.h"
 
 class GURL;
+class Extension;
 class ExtensionDevToolsManager;
 class Profile;
 class RenderProcessHost;
 
 class ExtensionEventRouter : public NotificationObserver {
  public:
+  // Returns true if the given extension can see events and data from another
+  // sub-profile (incognito to original profile, or vice versa).
+  static bool CanCrossIncognito(Profile* profile,
+                                const std::string& extension_id);
+  static bool CanCrossIncognito(Profile* profile, const Extension* extension);
+
   explicit ExtensionEventRouter(Profile* profile);
   ~ExtensionEventRouter();
 
diff --git a/chrome/browser/extensions/extension_menu_manager.cc b/chrome/browser/extensions/extension_menu_manager.cc
index 9ddb0f0e051a4a9c8e391e74d5d3f663e347dc99..eae74f6697f65cf3bc81d28c9c1939a8a25be5a3 100644
--- a/chrome/browser/extensions/extension_menu_manager.cc
+++ b/chrome/browser/extensions/extension_menu_manager.cc
@@ -389,9 +389,9 @@ void ExtensionMenuManager::ExecuteCommand(
   ListValue args;
 
   DictionaryValue* properties = new DictionaryValue();
-  properties->SetInteger("menuItemId", item->id().second);
+  properties->SetInteger("menuItemId", item->id().uid);
   if (item->parent_id())
-    properties->SetInteger("parentMenuItemId", item->parent_id()->second);
+    properties->SetInteger("parentMenuItemId", item->parent_id()->uid);
 
   switch (params.media_type) {
     case WebKit::WebContextMenuData::MediaTypeImage:
@@ -471,3 +471,36 @@ bool ExtensionMenuManager::HasAllowedScheme(const GURL& url) {
   URLPattern pattern(kAllowedSchemes);
   return pattern.SetScheme(url.scheme());
 }
+
+ExtensionMenuItem::Id::Id()
+    : profile(NULL), uid(0) {
+}
+
+ExtensionMenuItem::Id::Id(Profile* profile, std::string extension_id, int uid)
+    : profile(profile), extension_id(extension_id), uid(uid) {
+}
+
+ExtensionMenuItem::Id::~Id() {
+}
+
+bool ExtensionMenuItem::Id::operator==(const Id& other) const {
+  return (profile == other.profile &&
+          extension_id == other.extension_id &&
+          uid == other.uid);
+}
+
+bool ExtensionMenuItem::Id::operator!=(const Id& other) const {
+  return !(*this == other);
+}
+
+bool ExtensionMenuItem::Id::operator<(const Id& other) const {
+  if (profile < other.profile)
+    return true;
+  if (profile == other.profile) {
+    if (extension_id < other.extension_id)
+      return true;
+    if (extension_id == other.extension_id)
+      return uid < other.uid;
+  }
+  return false;
+}
diff --git a/chrome/browser/extensions/extension_menu_manager.h b/chrome/browser/extensions/extension_menu_manager.h
index 4455ee1a16cc6c56d78a8c18b108ada2efb0e9f7..c8224d11dd70d3990bbb94822624b787f68faa83 100644
--- a/chrome/browser/extensions/extension_menu_manager.h
+++ b/chrome/browser/extensions/extension_menu_manager.h
@@ -33,9 +33,20 @@ class ExtensionMenuItem {
   // A list of ExtensionMenuItem's.
   typedef std::vector<ExtensionMenuItem*> List;
 
-  // An Id is a pair of |extension id|, |int| where the |int| is unique per
-  // extension.
-  typedef std::pair<std::string, int> Id;
+  // An Id uniquely identifies a context menu item registered by an extension.
+  struct Id {
+    Id();
+    Id(Profile* profile, std::string extension_id, int uid);
+    ~Id();
+
+    bool operator==(const Id& other) const;
+    bool operator!=(const Id& other) const;
+    bool operator<(const Id& other) const;
+
+    Profile* profile;
+    std::string extension_id;
+    int uid;
+  };
 
   // For context menus, these are the contexts where an item can appear.
   enum Context {
@@ -93,7 +104,7 @@ class ExtensionMenuItem {
   virtual ~ExtensionMenuItem();
 
   // Simple accessor methods.
-  const std::string& extension_id() const { return id_.first; }
+  const std::string& extension_id() const { return id_.extension_id; }
   const std::string& title() const { return title_; }
   const List& children() { return children_; }
   const Id& id() const { return id_; }
diff --git a/chrome/browser/extensions/extension_menu_manager_unittest.cc b/chrome/browser/extensions/extension_menu_manager_unittest.cc
index 549c24570338b0ab17e6a90d4db97b7e606f8aa9..cbd9a52835f2da3bb86db16fbff84f6550ae5648 100644
--- a/chrome/browser/extensions/extension_menu_manager_unittest.cc
+++ b/chrome/browser/extensions/extension_menu_manager_unittest.cc
@@ -37,7 +37,7 @@ class ExtensionMenuManagerTest : public testing::Test {
   ExtensionMenuItem* CreateTestItem(Extension* extension) {
     ExtensionMenuItem::Type type = ExtensionMenuItem::NORMAL;
     ExtensionMenuItem::ContextList contexts(ExtensionMenuItem::ALL);
-    ExtensionMenuItem::Id id(extension->id(), next_id_++);
+    ExtensionMenuItem::Id id(NULL, extension->id(), next_id_++);
     return new ExtensionMenuItem(id, "test", false, type, contexts);
   }
 
@@ -94,7 +94,7 @@ TEST_F(ExtensionMenuManagerTest, AddGetRemoveItems) {
   ASSERT_EQ(2u, manager_.MenuItems(extension_id)->size());
 
   // Make sure removing a non-existent item returns false.
-  ExtensionMenuItem::Id id(extension->id(), id3.second + 50);
+  ExtensionMenuItem::Id id(NULL, extension->id(), id3.uid + 50);
   ASSERT_FALSE(manager_.RemoveContextMenuItem(id));
 }
 
@@ -461,7 +461,7 @@ TEST_F(ExtensionMenuManagerTest, ExecuteCommand) {
 
   int tmp_id = 0;
   ASSERT_TRUE(info->GetInteger("menuItemId", &tmp_id));
-  ASSERT_EQ(id.second, tmp_id);
+  ASSERT_EQ(id.uid, tmp_id);
 
   std::string tmp;
   ASSERT_TRUE(info->GetString("mediaType", &tmp));
diff --git a/chrome/browser/extensions/extension_tabs_module.cc b/chrome/browser/extensions/extension_tabs_module.cc
index 35988088c934ec64b66a1db1eac89a0414963f8a..11d5f31a1eadec464057d86ef2616371a810c89a 100644
--- a/chrome/browser/extensions/extension_tabs_module.cc
+++ b/chrome/browser/extensions/extension_tabs_module.cc
@@ -598,9 +598,10 @@ bool CreateTabFunction::RunImpl() {
     EXTENSION_FUNCTION_VALIDATE(args->GetBoolean(keys::kSelectedKey,
                                                  &selected));
 
-  // We can't load extension URLs into incognito windows. Special case to
-  // fall back to a normal window.
+  // We can't load extension URLs into incognito windows unless the extension
+  // uses split mode. Special case to fall back to a normal window.
   if (url.SchemeIs(chrome::kExtensionScheme) &&
+      !GetExtension()->incognito_split_mode() &&
       browser->profile()->IsOffTheRecord()) {
     Profile* profile = browser->profile()->GetOriginalProfile();
     browser = BrowserList::FindBrowserWithType(profile,
diff --git a/chrome/browser/extensions/extension_test_message_listener.cc b/chrome/browser/extensions/extension_test_message_listener.cc
index 423bf3b10a7feef61c0f4bfc50c388023d54d265..8ba0683461efe4fab6b4bd5e62ba65f70008a55f 100644
--- a/chrome/browser/extensions/extension_test_message_listener.cc
+++ b/chrome/browser/extensions/extension_test_message_listener.cc
@@ -43,8 +43,8 @@ void ExtensionTestMessageListener::Observe(
     const NotificationSource& source,
     const NotificationDetails& details) {
   const std::string& content = *Details<std::string>(details).ptr();
-  function_ = Source<ExtensionTestSendMessageFunction>(source).ptr();
   if (!satisfied_ && content == expected_message_) {
+    function_ = Source<ExtensionTestSendMessageFunction>(source).ptr();
     satisfied_ = true;
     registrar_.RemoveAll();  // Stop listening for more messages.
     if (!will_reply_) {
diff --git a/chrome/browser/extensions/extension_test_message_listener.h b/chrome/browser/extensions/extension_test_message_listener.h
index bead446aba608dd7d20f54371cdbe85d38a7da21..86c4cf26ca9e352c9f85a35150d1d8643aad121c 100644
--- a/chrome/browser/extensions/extension_test_message_listener.h
+++ b/chrome/browser/extensions/extension_test_message_listener.h
@@ -63,6 +63,8 @@ class ExtensionTestMessageListener : public NotificationObserver {
                        const NotificationSource& source,
                        const NotificationDetails& details);
 
+  bool was_satisfied() const { return satisfied_; }
+
  private:
   NotificationRegistrar registrar_;
 
diff --git a/chrome/browser/tab_contents/render_view_context_menu.cc b/chrome/browser/tab_contents/render_view_context_menu.cc
index afd5ccbdc6039d45d026ff66c714b591a170a538..f792b359d7f8e69e85f1cc5e197284c81cec3c2e 100644
--- a/chrome/browser/tab_contents/render_view_context_menu.cc
+++ b/chrome/browser/tab_contents/render_view_context_menu.cc
@@ -23,6 +23,7 @@
 #include "chrome/browser/debugger/devtools_manager.h"
 #include "chrome/browser/debugger/devtools_window.h"
 #include "chrome/browser/download/download_manager.h"
+#include "chrome/browser/extensions/extension_event_router.h"
 #include "chrome/browser/extensions/extensions_service.h"
 #include "chrome/browser/fonts_languages_window.h"
 #include "chrome/browser/metrics/user_metrics.h"
@@ -150,10 +151,12 @@ static const GURL& GetDocumentURL(const ContextMenuParams& params) {
 }
 
 // Given a list of items, returns the ones that match given the contents
-// of |params|.
+// of |params| and the profile.
 static ExtensionMenuItem::List GetRelevantExtensionItems(
     const ExtensionMenuItem::List& items,
-    const ContextMenuParams& params) {
+    const ContextMenuParams& params,
+    Profile* profile,
+    bool can_cross_incognito) {
   ExtensionMenuItem::List result;
   for (ExtensionMenuItem::List::const_iterator i = items.begin();
        i != items.end(); ++i) {
@@ -171,7 +174,8 @@ static ExtensionMenuItem::List GetRelevantExtensionItems(
     if (!ExtensionPatternMatch(item->target_url_patterns(), target_url))
       continue;
 
-    result.push_back(*i);
+    if (item->id().profile == profile || can_cross_incognito)
+      result.push_back(*i);
   }
   return result;
 }
@@ -181,6 +185,8 @@ void RenderViewContextMenu::AppendExtensionItems(
   ExtensionsService* service = profile_->GetExtensionsService();
   ExtensionMenuManager* manager = service->menu_manager();
   const Extension* extension = service->GetExtensionById(extension_id, false);
+  bool can_cross_incognito =
+      ExtensionEventRouter::CanCrossIncognito(profile_, extension);
   DCHECK_GE(*index, 0);
   int max_index =
       IDC_EXTENSIONS_CONTEXT_CUSTOM_LAST - IDC_EXTENSIONS_CONTEXT_CUSTOM_FIRST;
@@ -192,7 +198,8 @@ void RenderViewContextMenu::AppendExtensionItems(
   if (!all_items || all_items->empty())
     return;
   ExtensionMenuItem::List items =
-      GetRelevantExtensionItems(*all_items, params_);
+      GetRelevantExtensionItems(*all_items, params_, profile_,
+                                can_cross_incognito);
   if (items.empty())
     return;
 
@@ -215,7 +222,8 @@ void RenderViewContextMenu::AppendExtensionItems(
     extension_item_map_[menu_id] = item->id();
     title = item->TitleWithReplacement(PrintableSelectionText(),
                                        kMaxExtensionItemTitleLength);
-    submenu_items = GetRelevantExtensionItems(item->children(), params_);
+    submenu_items = GetRelevantExtensionItems(item->children(), params_,
+                                              profile_, can_cross_incognito);
   }
 
   // Now add our item(s) to the menu_model_.
@@ -225,13 +233,15 @@ void RenderViewContextMenu::AppendExtensionItems(
     menus::SimpleMenuModel* submenu = new menus::SimpleMenuModel(this);
     extension_menu_models_.push_back(submenu);
     menu_model_.AddSubMenu(menu_id, title, submenu);
-    RecursivelyAppendExtensionItems(submenu_items, submenu, index);
+    RecursivelyAppendExtensionItems(submenu_items, can_cross_incognito, submenu,
+                                    index);
   }
   SetExtensionIcon(extension_id);
 }
 
 void RenderViewContextMenu::RecursivelyAppendExtensionItems(
     const ExtensionMenuItem::List& items,
+    bool can_cross_incognito,
     menus::SimpleMenuModel* menu_model,
     int *index) {
   string16 selection_text = PrintableSelectionText();
@@ -258,14 +268,16 @@ void RenderViewContextMenu::RecursivelyAppendExtensionItems(
                                                 kMaxExtensionItemTitleLength);
     if (item->type() == ExtensionMenuItem::NORMAL) {
       ExtensionMenuItem::List children =
-          GetRelevantExtensionItems(item->children(), params_);
+          GetRelevantExtensionItems(item->children(), params_,
+                                    profile_, can_cross_incognito);
       if (children.size() == 0) {
         menu_model->AddItem(menu_id, title);
       } else {
         menus::SimpleMenuModel* submenu = new menus::SimpleMenuModel(this);
         extension_menu_models_.push_back(submenu);
         menu_model->AddSubMenu(menu_id, title, submenu);
-        RecursivelyAppendExtensionItems(children, submenu, index);
+        RecursivelyAppendExtensionItems(children, can_cross_incognito,
+                                        submenu, index);
       }
     } else if (item->type() == ExtensionMenuItem::CHECKBOX) {
       menu_model->AddCheckItem(menu_id, title);
diff --git a/chrome/browser/tab_contents/render_view_context_menu.h b/chrome/browser/tab_contents/render_view_context_menu.h
index 9fd3108fb22425abe0c754bd1e603422ba45b5d7..2f1a83e899656575d0052744fed8d76ac54a65c2 100644
--- a/chrome/browser/tab_contents/render_view_context_menu.h
+++ b/chrome/browser/tab_contents/render_view_context_menu.h
@@ -103,6 +103,7 @@ class RenderViewContextMenu : public menus::SimpleMenuModel::Delegate {
   // Used for recursively adding submenus of extension items.
   void RecursivelyAppendExtensionItems(
       const std::vector<ExtensionMenuItem*>& items,
+      bool can_cross_incognito,
       menus::SimpleMenuModel* menu_model,
       int *index);
   // This will set the icon on the most recently-added item in the menu_model_.
diff --git a/chrome/test/data/extensions/context_menus/incognito/background.html b/chrome/test/data/extensions/context_menus/incognito/background.html
new file mode 100644
index 0000000000000000000000000000000000000000..46f4d74c30692c8ab193b54683da02bd212ef91f
--- /dev/null
+++ b/chrome/test/data/extensions/context_menus/incognito/background.html
@@ -0,0 +1 @@
+<script src="test.js"></script>
diff --git a/chrome/test/data/extensions/context_menus/incognito/manifest.json b/chrome/test/data/extensions/context_menus/incognito/manifest.json
new file mode 100644
index 0000000000000000000000000000000000000000..560ca1300cc8d6609cd77a018b68cef5c81a51ee
--- /dev/null
+++ b/chrome/test/data/extensions/context_menus/incognito/manifest.json
@@ -0,0 +1,7 @@
+{
+  "name": "Tests that context menus work properly in incognito split mode",
+  "version": "0.1",
+  "permissions": ["contextMenus"],
+  "incognito": "split",
+  "background_page": "background.html"
+}
diff --git a/chrome/test/data/extensions/context_menus/incognito/test.js b/chrome/test/data/extensions/context_menus/incognito/test.js
new file mode 100644
index 0000000000000000000000000000000000000000..c64b01a36adb066af595813c26981945f84d9274
--- /dev/null
+++ b/chrome/test/data/extensions/context_menus/incognito/test.js
@@ -0,0 +1,19 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+var inIncognitoContext = chrome.extension.inIncognitoContext;
+var incognitoStr = inIncognitoContext ? "incognito" : "regular";
+
+function onclick(info) {
+  chrome.test.sendMessage("onclick fired " + incognitoStr);
+}
+
+window.onload = function() {
+  chrome.contextMenus.create({title: "item " + incognitoStr,
+                              onclick: onclick}, function() {
+    if (!chrome.extension.lastError) {
+      chrome.test.sendMessage("created item " + incognitoStr);
+    }
+  });
+};