diff --git a/src/webenginewidgets/api/qwebenginepage.cpp b/src/webenginewidgets/api/qwebenginepage.cpp
index b082f219df2e3ad9a1068bedfecc7224f8f1c2d7..9636598e8ba471dcdf301f18255748f256379c87 100644
--- a/src/webenginewidgets/api/qwebenginepage.cpp
+++ b/src/webenginewidgets/api/qwebenginepage.cpp
@@ -45,6 +45,82 @@
 
 QT_BEGIN_NAMESPACE
 
+CallbackDirectory::~CallbackDirectory()
+{
+    // "Cancel" pending callbacks by calling them with an invalid value.
+    // This guarantees that each callback is called exactly once.
+    Q_FOREACH (const CallbackSharedDataPointer &sharedPtr, m_callbackMap) {
+        switch (sharedPtr.type) {
+        case CallbackSharedDataPointer::Variant:
+            (*sharedPtr.variantCallback)(QVariant());
+            break;
+        case CallbackSharedDataPointer::String:
+            (*sharedPtr.stringCallback)(QString());
+            break;
+        default:
+            Q_UNREACHABLE();
+        }
+    }
+}
+
+void CallbackDirectory::registerCallback(quint64 requestId, const QExplicitlySharedDataPointer<VariantCallback> &callback)
+{
+    m_callbackMap.insert(requestId, CallbackSharedDataPointer(callback.data()));
+}
+
+void CallbackDirectory::registerCallback(quint64 requestId, const QExplicitlySharedDataPointer<StringCallback> &callback)
+{
+    m_callbackMap.insert(requestId, CallbackSharedDataPointer(callback.data()));
+}
+
+void CallbackDirectory::invoke(quint64 requestId, const QVariant &result)
+{
+    CallbackSharedDataPointer sharedPtr = m_callbackMap.take(requestId);
+    if (sharedPtr) {
+        Q_ASSERT(sharedPtr.type == CallbackSharedDataPointer::Variant);
+        (*sharedPtr.variantCallback)(result);
+    }
+}
+
+void CallbackDirectory::invoke(quint64 requestId, const QString &result)
+{
+    CallbackSharedDataPointer sharedPtr = m_callbackMap.take(requestId);
+    if (sharedPtr) {
+        Q_ASSERT(sharedPtr.type == CallbackSharedDataPointer::String);
+        (*sharedPtr.stringCallback)(result);
+    }
+}
+
+void CallbackDirectory::CallbackSharedDataPointer::doRef()
+{
+    switch (type) {
+    case None:
+        break;
+    case Variant:
+        variantCallback->ref.ref();
+        break;
+    case String:
+        stringCallback->ref.ref();
+        break;
+    }
+}
+
+void CallbackDirectory::CallbackSharedDataPointer::doDeref()
+{
+    switch (type) {
+    case None:
+        break;
+    case Variant:
+        if (!variantCallback->ref.deref())
+            delete variantCallback;
+        break;
+    case String:
+        if (!stringCallback->ref.deref())
+            delete stringCallback;
+        break;
+    }
+}
+
 QWebEnginePagePrivate::QWebEnginePagePrivate()
     : QObjectPrivate(QObjectPrivateVersion)
     , adapter(new WebContentsAdapter(SoftwareRenderingMode))
@@ -57,15 +133,6 @@ QWebEnginePagePrivate::QWebEnginePagePrivate()
 
 QWebEnginePagePrivate::~QWebEnginePagePrivate()
 {
-    // "Cancel" pending callbacks by calling them with an invalid value.
-    // This guarantees that each callback is called exactly once.
-    Q_FOREACH (QExplicitlySharedDataPointer<VariantCallback> callback, m_variantCallbacks)
-        (*callback)(QVariant());
-    m_variantCallbacks.clear();
-    Q_FOREACH (QExplicitlySharedDataPointer<StringCallback> callback, m_stringCallbacks)
-        (*callback)(QString());
-    m_stringCallbacks.clear();
-
     delete history;
 }
 
@@ -165,20 +232,17 @@ void QWebEnginePagePrivate::close()
 
 void QWebEnginePagePrivate::didRunJavaScript(quint64 requestId, const QVariant& result)
 {
-    if (QExplicitlySharedDataPointer<VariantCallback> callback = m_variantCallbacks.take(requestId))
-        (*callback)(result);
+    m_callbacks.invoke(requestId, result);
 }
 
 void QWebEnginePagePrivate::didFetchDocumentMarkup(quint64 requestId, const QString& result)
 {
-    if (QExplicitlySharedDataPointer<StringCallback> callback = m_stringCallbacks.take(requestId))
-        (*callback)(result);
+    m_callbacks.invoke(requestId, result);
 }
 
 void QWebEnginePagePrivate::didFetchDocumentInnerText(quint64 requestId, const QString& result)
 {
-    if (QExplicitlySharedDataPointer<StringCallback> callback = m_stringCallbacks.take(requestId))
-        (*callback)(result);
+    m_callbacks.invoke(requestId, result);
 }
 
 void QWebEnginePagePrivate::updateAction(QWebEnginePage::WebAction action) const
@@ -512,14 +576,14 @@ void QWebEnginePage::toHtml(const QWebEngineCallback<const QString &> &resultCal
 {
     Q_D(const QWebEnginePage);
     quint64 requestId = d->adapter->fetchDocumentMarkup();
-    d->m_stringCallbacks.insert(requestId, resultCallback.d);
+    d->m_callbacks.registerCallback(requestId, resultCallback.d);
 }
 
 void QWebEnginePage::toPlainText(const QWebEngineCallback<const QString &> &resultCallback) const
 {
     Q_D(const QWebEnginePage);
     quint64 requestId = d->adapter->fetchDocumentInnerText();
-    d->m_stringCallbacks.insert(requestId, resultCallback.d);
+    d->m_callbacks.registerCallback(requestId, resultCallback.d);
 }
 
 void QWebEnginePage::setHtml(const QString &html, const QUrl &baseUrl)
@@ -611,7 +675,7 @@ void QWebEnginePage::runJavaScript(const QString& scriptSource, const QWebEngine
 {
     Q_D(QWebEnginePage);
     quint64 requestId = d->adapter->runJavaScriptCallbackResult(scriptSource, xPath);
-    d->m_variantCallbacks.insert(requestId, resultCallback.d);
+    d->m_callbacks.registerCallback(requestId, resultCallback.d);
 }
 
 QWebEnginePage *QWebEnginePage::createWindow(WebWindowType type)
diff --git a/src/webenginewidgets/api/qwebenginepage_p.h b/src/webenginewidgets/api/qwebenginepage_p.h
index 86605c78d06542ee5cd08de26780b10aa5964541..9a4dc57fd46bb60e4097a4aca403c216e52088b2 100644
--- a/src/webenginewidgets/api/qwebenginepage_p.h
+++ b/src/webenginewidgets/api/qwebenginepage_p.h
@@ -58,6 +58,43 @@ class QWebEngineHistory;
 class QWebEnginePage;
 class QWebEngineView;
 
+class CallbackDirectory {
+public:
+    typedef QtWebEnginePrivate::QWebEngineCallbackPrivateBase<const QVariant&> VariantCallback;
+    typedef QtWebEnginePrivate::QWebEngineCallbackPrivateBase<const QString&> StringCallback;
+
+    ~CallbackDirectory();
+    void registerCallback(quint64 requestId, const QExplicitlySharedDataPointer<VariantCallback> &callback);
+    void registerCallback(quint64 requestId, const QExplicitlySharedDataPointer<StringCallback> &callback);
+    void invoke(quint64 requestId, const QVariant &result);
+    void invoke(quint64 requestId, const QString &result);
+
+private:
+    struct CallbackSharedDataPointer {
+        enum {
+            None,
+            Variant,
+            String
+        } type;
+        union {
+            VariantCallback *variantCallback;
+            StringCallback *stringCallback;
+        };
+        CallbackSharedDataPointer() : type(None) { }
+        CallbackSharedDataPointer(VariantCallback *callback) : type(Variant), variantCallback(callback) { callback->ref.ref(); }
+        CallbackSharedDataPointer(StringCallback *callback) : type(String), stringCallback(callback) { callback->ref.ref(); }
+        CallbackSharedDataPointer(const CallbackSharedDataPointer &other) : type(other.type), variantCallback(other.variantCallback) { doRef(); }
+        ~CallbackSharedDataPointer() { doDeref(); }
+        operator bool () const { return type != None; }
+
+    private:
+        void doRef();
+        void doDeref();
+    };
+
+    QHash<quint64, CallbackSharedDataPointer> m_callbackMap;
+};
+
 class QWebEnginePagePrivate : public QObjectPrivate, public WebContentsAdapterClient
 {
 public:
@@ -104,10 +141,7 @@ public:
     WebEngineContextMenuData m_menuData;
     QPointer<RenderWidgetHostViewQtDelegateWebPage> m_rwhvDelegate;
 
-    typedef QtWebEnginePrivate::QWebEngineCallbackPrivateBase<const QVariant&> VariantCallback;
-    typedef QtWebEnginePrivate::QWebEngineCallbackPrivateBase<const QString&> StringCallback;
-    mutable QHash<quint64, QExplicitlySharedDataPointer<VariantCallback> > m_variantCallbacks;
-    mutable QHash<quint64, QExplicitlySharedDataPointer<StringCallback> > m_stringCallbacks;
+    mutable CallbackDirectory m_callbacks;
 };
 
 QT_END_NAMESPACE