diff --git content/browser/frame_host/render_frame_host_manager.cc content/browser/frame_host/render_frame_host_manager.cc
index 0663535e3f81..e0e20722c820 100644
--- content/browser/frame_host/render_frame_host_manager.cc
+++ content/browser/frame_host/render_frame_host_manager.cc
@@ -1082,10 +1082,11 @@ bool RenderFrameHostManager::ShouldSwapBrowsingInstancesForNavigation(
   // TODO(alexmos): This check should've been enforced earlier in the
   // navigation, in chrome::Navigate().  Verify this, and then convert this to
   // a CHECK and remove the fallback.
-  DCHECK_EQ(browser_context,
-            render_frame_host_->GetSiteInstance()->GetBrowserContext());
-  if (browser_context !=
-      render_frame_host_->GetSiteInstance()->GetBrowserContext()) {
+  const bool is_same = GetContentClient()->browser()->IsSameBrowserContext(
+      browser_context,
+      render_frame_host_->GetSiteInstance()->GetBrowserContext());
+  DCHECK(is_same);
+  if (!is_same) {
     return true;
   }
 
@@ -1224,7 +1225,8 @@ RenderFrameHostManager::GetSiteInstanceForNavigation(
 
   // Double-check that the new SiteInstance is associated with the right
   // BrowserContext.
-  DCHECK_EQ(new_instance->GetBrowserContext(), browser_context);
+  DCHECK(GetContentClient()->browser()->IsSameBrowserContext(
+      new_instance->GetBrowserContext(), browser_context));
 
   // If |new_instance| is a new SiteInstance for a subframe with an isolated
   // origin, set its process reuse policy so that such subframes are
diff --git content/public/browser/content_browser_client.h content/public/browser/content_browser_client.h
index e56b320170df..26aa6fe50311 100644
--- content/public/browser/content_browser_client.h
+++ content/public/browser/content_browser_client.h
@@ -343,6 +343,13 @@ class CONTENT_EXPORT ContentBrowserClient {
                                               const GURL& current_url,
                                               const GURL& new_url);
 
+  // Returns true if two browser contexts should be considered the same. CEF
+  // uses this to treat *Impl and *Proxy contexts as the same.
+  virtual bool IsSameBrowserContext(BrowserContext* context1,
+                                    BrowserContext* context2) {
+    return context1 == context2;
+  }
+
   // Returns true if the passed in URL should be assigned as the site of the
   // current SiteInstance, if it does not yet have a site.
   virtual bool ShouldAssignSiteForURL(const GURL& url);
diff --git extensions/browser/extension_host.cc extensions/browser/extension_host.cc
index e85940e1123a..7d4e3c13204b 100644
--- extensions/browser/extension_host.cc
+++ extensions/browser/extension_host.cc
@@ -69,11 +69,12 @@ ExtensionHost::ExtensionHost(const Extension* extension,
   DCHECK(host_type == VIEW_TYPE_EXTENSION_BACKGROUND_PAGE ||
          host_type == VIEW_TYPE_EXTENSION_DIALOG ||
          host_type == VIEW_TYPE_EXTENSION_POPUP);
-  host_contents_.reset(WebContents::Create(
-      WebContents::CreateParams(browser_context_, site_instance))),
-  content::WebContentsObserver::Observe(host_contents_.get());
+  host_contents_owned_.reset(WebContents::Create(
+      WebContents::CreateParams(browser_context_, site_instance)));
+  host_contents_ = host_contents_owned_.get();
+  content::WebContentsObserver::Observe(host_contents_);
   host_contents_->SetDelegate(this);
-  SetViewType(host_contents_.get(), host_type);
+  SetViewType(host_contents_, host_type);
 
   render_view_host_ = host_contents_->GetRenderViewHost();
 
@@ -88,6 +89,48 @@ ExtensionHost::ExtensionHost(const Extension* extension,
       dispatcher()->set_delegate(this);
 }
 
+ExtensionHost::ExtensionHost(ExtensionHostDelegate* delegate,
+                             const Extension* extension,
+                             content::BrowserContext* browser_context,
+                             content::WebContents* host_contents,
+                             const GURL& url,
+                             ViewType host_type)
+    : delegate_(delegate),
+      extension_(extension),
+      extension_id_(extension->id()),
+      browser_context_(browser_context),
+      host_contents_(host_contents),
+      render_view_host_(nullptr),
+      is_render_view_creation_pending_(false),
+      has_loaded_once_(false),
+      document_element_available_(false),
+      initial_url_(url),
+      extension_host_type_(host_type) {
+  DCHECK(delegate);
+  DCHECK(browser_context);
+  DCHECK(host_contents);
+
+  // Not used for panels, see PanelHost.
+  DCHECK(host_type == VIEW_TYPE_EXTENSION_BACKGROUND_PAGE ||
+         host_type == VIEW_TYPE_EXTENSION_DIALOG ||
+         host_type == VIEW_TYPE_EXTENSION_POPUP);
+
+  content::WebContentsObserver::Observe(host_contents_);
+  SetViewType(host_contents_, host_type);
+
+  render_view_host_ = host_contents_->GetRenderViewHost();
+
+  // Listen for when an extension is unloaded from the same profile, as it may
+  // be the same extension that this points to.
+  ExtensionRegistry::Get(browser_context_)->AddObserver(this);
+
+  // Set up web contents observers and pref observers.
+  delegate_->OnExtensionHostCreated(host_contents_);
+
+  ExtensionWebContentsObserver::GetForWebContents(host_contents_)->
+      dispatcher()->set_delegate(this);
+}
+
 ExtensionHost::~ExtensionHost() {
   ExtensionRegistry::Get(browser_context_)->RemoveObserver(this);
 
diff --git extensions/browser/extension_host.h extensions/browser/extension_host.h
index 34812c083bf5..1ccfaf6e1c45 100644
--- extensions/browser/extension_host.h
+++ extensions/browser/extension_host.h
@@ -51,13 +51,19 @@ class ExtensionHost : public DeferredStartRenderHost,
   ExtensionHost(const Extension* extension,
                 content::SiteInstance* site_instance,
                 const GURL& url, ViewType host_type);
+  ExtensionHost(ExtensionHostDelegate* delegate,
+                const Extension* extension,
+                content::BrowserContext* browser_context,
+                content::WebContents* host_contents,
+                const GURL& url,
+                ViewType host_type);
   ~ExtensionHost() override;
 
   // This may be null if the extension has been or is being unloaded.
   const Extension* extension() const { return extension_; }
 
   const std::string& extension_id() const { return extension_id_; }
-  content::WebContents* host_contents() const { return host_contents_.get(); }
+  content::WebContents* host_contents() const { return host_contents_; }
   content::RenderViewHost* render_view_host() const;
   content::RenderProcessHost* render_process_host() const;
   bool has_loaded_once() const { return has_loaded_once_; }
@@ -175,7 +181,8 @@ class ExtensionHost : public DeferredStartRenderHost,
   content::BrowserContext* browser_context_;
 
   // The host for our HTML content.
-  std::unique_ptr<content::WebContents> host_contents_;
+  std::unique_ptr<content::WebContents> host_contents_owned_;
+  content::WebContents* host_contents_;
 
   // A weak pointer to the current or pending RenderViewHost. We don't access
   // this through the host_contents because we want to deal with the pending
diff --git extensions/browser/extensions_browser_client.h extensions/browser/extensions_browser_client.h
index 69434c704f2f..f31b65fcd192 100644
--- extensions/browser/extensions_browser_client.h
+++ extensions/browser/extensions_browser_client.h
@@ -53,6 +53,7 @@ class ComponentExtensionResourceManager;
 class Extension;
 class ExtensionCache;
 class ExtensionError;
+class ExtensionHost;
 class ExtensionHostDelegate;
 class ExtensionPrefsObserver;
 class ExtensionApiFrameIdMap;
@@ -108,6 +109,11 @@ class ExtensionsBrowserClient {
   virtual content::BrowserContext* GetOriginalContext(
       content::BrowserContext* context) = 0;
 
+  // Returns the CEF *Impl context. Used in cases where we want special CEF
+  // handling without interfering with the side-by-side Chrome build.
+  virtual content::BrowserContext* GetCefImplContext(
+      content::BrowserContext* context) { return nullptr; }
+
 #if defined(OS_CHROMEOS)
   // Returns a user id hash from |context| or an empty string if no hash could
   // be extracted.
@@ -173,6 +179,14 @@ class ExtensionsBrowserClient {
   virtual std::unique_ptr<ExtensionHostDelegate>
   CreateExtensionHostDelegate() = 0;
 
+  // CEF creates a custom ExtensionHost for background pages. If the return
+  // value is true and |host| is NULL then fail the background host creation.
+  virtual bool CreateBackgroundExtensionHost(
+      const Extension* extension,
+      content::BrowserContext* browser_context,
+      const GURL& url,
+      ExtensionHost** host) { return false; }
+
   // Returns true if the client version has updated since the last run. Called
   // once each time the extensions system is loaded per browser_context. The
   // implementation may wish to use the BrowserContext to record the current
diff --git extensions/browser/process_manager.cc extensions/browser/process_manager.cc
index 5a06db3d4495..b960853f02b2 100644
--- extensions/browser/process_manager.cc
+++ extensions/browser/process_manager.cc
@@ -349,9 +349,16 @@ bool ProcessManager::CreateBackgroundHost(const Extension* extension,
     return true;  // TODO(kalman): return false here? It might break things...
 
   DVLOG(1) << "CreateBackgroundHost " << extension->id();
-  ExtensionHost* host =
-      new ExtensionHost(extension, GetSiteInstanceForURL(url).get(), url,
-                        VIEW_TYPE_EXTENSION_BACKGROUND_PAGE);
+  ExtensionHost* host = nullptr;
+  if (ExtensionsBrowserClient::Get()->CreateBackgroundExtensionHost(
+          extension, browser_context_, url, &host) && !host) {
+    // Explicitly fail if the client can't create the host.
+    return false;
+  }
+  if (!host) {
+    host = new ExtensionHost(extension, GetSiteInstanceForURL(url).get(), url,
+                             VIEW_TYPE_EXTENSION_BACKGROUND_PAGE);
+  }
   host->CreateRenderViewSoon();
   OnBackgroundHostCreated(host);
   return true;
diff --git extensions/browser/process_manager_factory.cc extensions/browser/process_manager_factory.cc
index e8929c5da255..5ae43b4361a4 100644
--- extensions/browser/process_manager_factory.cc
+++ extensions/browser/process_manager_factory.cc
@@ -5,6 +5,7 @@
 #include "extensions/browser/process_manager_factory.h"
 
 #include "components/keyed_service/content/browser_context_dependency_manager.h"
+#include "extensions/browser/extensions_browser_client.h"
 #include "extensions/browser/extension_registry_factory.h"
 #include "extensions/browser/lazy_background_task_queue_factory.h"
 #include "extensions/browser/process_manager.h"
@@ -50,6 +51,12 @@ KeyedService* ProcessManagerFactory::BuildServiceInstanceFor(
 
 BrowserContext* ProcessManagerFactory::GetBrowserContextToUse(
     BrowserContext* context) const {
+  // CEF wants all extension state routed to the *Impl context.
+  content::BrowserContext* cef_context =
+      ExtensionsBrowserClient::Get()->GetCefImplContext(context);
+  if (cef_context)
+    return cef_context;
+
   // ProcessManager::Create handles guest and incognito profiles, returning an
   // IncognitoProcessManager in incognito mode.
   return context;