diff --git a/src/corelib/json/qjson.cpp b/src/corelib/json/qjson.cpp
index d509349a51..10ca2de68c 100644
--- a/src/corelib/json/qjson.cpp
+++ b/src/corelib/json/qjson.cpp
@@ -308,6 +308,11 @@ int Value::usedStorage(const Base *b) const
 {
     int s = 0;
     switch (type) {
+    case QJsonValue::LongLong:
+        if (latinOrIntValue)
+            break;
+        s = sizeof(long long);
+        break;
     case QJsonValue::Double:
         if (latinOrIntValue)
             break;
@@ -337,6 +342,7 @@ bool Value::isValid(const Base *b) const
 {
     int offset = 0;
     switch (type) {
+    case QJsonValue::LongLong:
     case QJsonValue::Double:
         if (latinOrIntValue)
             break;
@@ -376,6 +382,12 @@ int Value::requiredStorage(QJsonValue &v, bool *compressed)
 {
     *compressed = false;
     switch (v.t) {
+    case QJsonValue::LongLong:
+        if (QJsonPrivate::compressedNumber(v.ll) != INT_MAX) {
+            *compressed = true;
+            return 0;
+        }
+        return sizeof(long long);
     case QJsonValue::Double:
         if (QJsonPrivate::compressedNumber(v.dbl) != INT_MAX) {
             *compressed = true;
@@ -414,12 +426,18 @@ uint Value::valueToStore(const QJsonValue &v, uint offset)
         break;
     case QJsonValue::Bool:
         return v.b;
+    case QJsonValue::LongLong: {
+        int c = QJsonPrivate::compressedNumber(v.ll);
+        if (c != INT_MAX)
+            return c;
+        return offset;
+    }
     case QJsonValue::Double: {
         int c = QJsonPrivate::compressedNumber(v.dbl);
         if (c != INT_MAX)
             return c;
+        return offset;
     }
-        Q_FALLTHROUGH();
     case QJsonValue::String:
     case QJsonValue::Array:
     case QJsonValue::Object:
@@ -434,6 +452,7 @@ uint Value::valueToStore(const QJsonValue &v, uint offset)
 void Value::copyData(const QJsonValue &v, char *dest, bool compressed)
 {
     switch (v.t) {
+    case QJsonValue::LongLong:
     case QJsonValue::Double:
         if (!compressed) {
             qToLittleEndian(v.ui, dest);
diff --git a/src/corelib/json/qjson_p.h b/src/corelib/json/qjson_p.h
index c012ec2662..1aad9b6490 100644
--- a/src/corelib/json/qjson_p.h
+++ b/src/corelib/json/qjson_p.h
@@ -318,6 +318,14 @@ static inline int compressedNumber(double d)
     return neg ? -res : res;
 }
 
+// returns INT_MAX if it can't compress it into 27 bits
+static inline int compressedNumber(long long d)
+{
+    if (d < -(1<<26) || d >= (1<<26))
+        return INT_MAX;
+    return d;
+}
+
 class Latin1String;
 
 class String
@@ -652,6 +660,7 @@ public:
 
     bool toBoolean() const;
     double toDouble(const Base *b) const;
+    long long toLongLong(const Base *b) const;
     QString toString(const Base *b) const;
     String asString(const Base *b) const;
     Latin1String asLatin1String(const Base *b) const;
@@ -784,6 +793,16 @@ inline double Value::toDouble(const Base *b) const
     return d;
 }
 
+inline long long Value::toLongLong(const Base *b) const
+{
+    Q_ASSERT(type == QJsonValue::LongLong);
+    if (latinOrIntValue)
+        return int_value;
+
+    quint64 i = qFromLittleEndian<quint64>((const uchar *)b + value);
+    return i;
+}
+
 inline String Value::asString(const Base *b) const
 {
     Q_ASSERT(type == QJsonValue::String && !latinOrIntValue);
diff --git a/src/corelib/json/qjsonparser.cpp b/src/corelib/json/qjsonparser.cpp
index 39738b90a8..7b42fb0a87 100644
--- a/src/corelib/json/qjsonparser.cpp
+++ b/src/corelib/json/qjsonparser.cpp
@@ -792,16 +792,27 @@ bool Parser::parseNumber(QJsonPrivate::Value *val, int baseOffset)
     bool ok;
     union {
         quint64 ui;
+        long long ll;
         double d;
     };
-    d = number.toDouble(&ok);
+    ll = number.toLongLong(&ok);
+    if (ok)
+        val->type = QJsonValue::LongLong;
+    else
+        d = number.toDouble(&ok);
 
     if (!ok) {
         lastError = QJsonParseError::IllegalNumber;
         return false;
     }
 
-    int pos = reserveSpace(sizeof(double));
+    // Prefer Double for backwards compatibility
+    if (val->type == (uint)QJsonValue::LongLong && qint64(double(ll)) == ll) {
+        d = ll;
+        val->type = QJsonValue::Double;
+    }
+
+    int pos = reserveSpace(sizeof(quint64));
     if (pos < 0)
         return false;
     qToLittleEndian(ui, data + pos);
diff --git a/src/corelib/json/qjsonvalue.cpp b/src/corelib/json/qjsonvalue.cpp
index 4b52014db1..67f7d6ef9e 100644
--- a/src/corelib/json/qjsonvalue.cpp
+++ b/src/corelib/json/qjsonvalue.cpp
@@ -126,6 +126,9 @@ QJsonValue::QJsonValue(QJsonPrivate::Data *data, QJsonPrivate::Base *base, const
     case Double:
         dbl = v.toDouble(base);
         break;
+    case LongLong:
+        ll = v.toLongLong(base);
+        break;
     case String: {
         QString s = v.toString(base);
         stringData = s.data_ptr();
@@ -174,12 +177,18 @@ QJsonValue::QJsonValue(int n)
     \overload
     Creates a value of type Double, with value \a n.
     NOTE: the integer limits for IEEE 754 double precision data is 2^53 (-9007199254740992 to +9007199254740992).
-    If you pass in values outside this range expect a loss of precision to occur.
+    If you pass in values outside this range the internal type will be LongLong.
  */
 QJsonValue::QJsonValue(qint64 n)
-    : d(0), t(Double)
+    : d(0)
 {
-    this->dbl = double(n);
+    if (qint64(double(n)) != n) {
+        t = LongLong;
+        ll = n;
+    } else {
+        t = Double;
+        dbl = double(n);
+    }
 }
 
 /*!
@@ -449,6 +458,7 @@ QJsonValue QJsonValue::fromVariant(const QVariant &variant)
     \value Null     QMetaType::Nullptr
     \value Bool     QMetaType::Bool
     \value Double   QMetaType::Double
+    \value LongLong QMetaType::LongLong
     \value String   QString
     \value Array    QVariantList
     \value Object   QVariantMap
@@ -461,6 +471,8 @@ QVariant QJsonValue::toVariant() const
     switch (t) {
     case Bool:
         return b;
+    case LongLong:
+        return ll;
     case Double:
         return dbl;
     case String:
@@ -492,6 +504,7 @@ QVariant QJsonValue::toVariant() const
     \value String   A string. Use toString() to convert to a QString.
     \value Array    An array. Use toArray() to convert to a QJsonArray.
     \value Object   An object. Use toObject() to convert to a QJsonObject.
+    \value LongLong A long long. Use toLongLong() to convert to a long long.
     \value Undefined The value is undefined. This is usually returned as an
                     error condition, when trying to read an out of bounds value
                     in an array or a non existent key in an object.
@@ -522,11 +535,13 @@ bool QJsonValue::toBool(bool defaultValue) const
 /*!
     Converts the value to an int and returns it.
 
-    If type() is not Double or the value is not a whole number,
-    the \a defaultValue will be returned.
+    If type() is not Double or LongLong or the value is not representable
+    as an integer, the \a defaultValue will be returned.
  */
 int QJsonValue::toInt(int defaultValue) const
 {
+    if (t == LongLong && int(ll) == ll)
+        return int(ll);
     if (t == Double && int(dbl) == dbl)
         return int(dbl);
     return defaultValue;
@@ -535,16 +550,32 @@ int QJsonValue::toInt(int defaultValue) const
 /*!
     Converts the value to a double and returns it.
 
-    If type() is not Double, the \a defaultValue will be returned.
+    If type() is not Double, or a LongLong representable as a double, the \a defaultValue will be returned.
  */
 double QJsonValue::toDouble(double defaultValue) const
 {
+    if (t == LongLong && qint64(double(ll)) == ll)
+        return ll;
     if (t != Double)
         return defaultValue;
     return dbl;
 }
 
 /*!
+    Converts the value to a long long and returns it.
+
+    If type() is not LongLong or Double with no fraction, the \a defaultValue will be returned.
+ */
+long long QJsonValue::toLongLong(long long defaultValue) const
+{
+    if (t == Double && qint64(dbl) == dbl)
+        return dbl;
+    if (t != LongLong)
+        return defaultValue;
+    return ll;
+}
+
+/*!
     Converts the value to a QString and returns it.
 
     If type() is not String, the \a defaultValue will be returned.
@@ -629,7 +660,7 @@ QJsonObject QJsonValue::toObject() const
  */
 bool QJsonValue::operator==(const QJsonValue &other) const
 {
-    if (t != other.t)
+    if (t != other.t && !(isNumber() && other.isNumber()))
         return false;
 
     switch (t) {
@@ -638,8 +669,10 @@ bool QJsonValue::operator==(const QJsonValue &other) const
         break;
     case Bool:
         return b == other.b;
+    case LongLong:
+        return ll == other.toLongLong();
     case Double:
-        return dbl == other.dbl;
+        return dbl == other.toDouble();
     case String:
         return toString() == other.toString();
     case Array:
@@ -772,6 +805,9 @@ QDebug operator<<(QDebug dbg, const QJsonValue &o)
     case QJsonValue::Double:
         dbg.nospace() << "QJsonValue(double, " << o.toDouble() << ')';
         break;
+    case QJsonValue::LongLong:
+        dbg.nospace() << "QJsonValue(long long, " << o.toLongLong() << ')';
+        break;
     case QJsonValue::String:
         dbg.nospace() << "QJsonValue(string, " << o.toString() << ')';
         break;
diff --git a/src/corelib/json/qjsonvalue.h b/src/corelib/json/qjsonvalue.h
index a853acaddd..3f15b25a46 100644
--- a/src/corelib/json/qjsonvalue.h
+++ b/src/corelib/json/qjsonvalue.h
@@ -70,6 +70,7 @@ public:
         String = 0x3,
         Array = 0x4,
         Object = 0x5,
+        LongLong = 0x6,
         Undefined = 0x80
     };
 
@@ -103,10 +104,12 @@ public:
     inline bool isArray() const { return type() == Array; }
     inline bool isObject() const { return type() == Object; }
     inline bool isUndefined() const { return type() == Undefined; }
+    inline bool isNumber() const { return type() == Double || type() == LongLong; }
 
     bool toBool(bool defaultValue = false) const;
     int toInt(int defaultValue = 0) const;
     double toDouble(double defaultValue = 0) const;
+    long long toLongLong(long long defaultValue = 0) const;
     QString toString() const;
     QString toString(const QString &defaultValue) const;
     QJsonArray toArray() const;
@@ -134,6 +137,7 @@ private:
         quint64 ui;
         bool b;
         double dbl;
+        qint64 ll;
         QStringData *stringData;
         QJsonPrivate::Base *base;
     };
@@ -162,6 +166,7 @@ public:
     inline bool isArray() const { return type() == QJsonValue::Array; }
     inline bool isObject() const { return type() == QJsonValue::Object; }
     inline bool isUndefined() const { return type() == QJsonValue::Undefined; }
+    inline bool isNumber() const { return type() == QJsonValue::Double || type() == QJsonValue::LongLong; }
 
     inline bool toBool() const { return toValue().toBool(); }
     inline int toInt() const { return toValue().toInt(); }
@@ -176,6 +181,8 @@ public:
     inline double toDouble(double defaultValue) const { return toValue().toDouble(defaultValue); }
     inline QString toString(const QString &defaultValue) const { return toValue().toString(defaultValue); }
 
+    inline long long toLongLong(long long defaultValue = 0) const { return toValue().toLongLong(defaultValue); }
+
     inline bool operator==(const QJsonValue &other) const { return toValue() == other; }
     inline bool operator!=(const QJsonValue &other) const { return toValue() != other; }
 
diff --git a/src/corelib/json/qjsonwriter.cpp b/src/corelib/json/qjsonwriter.cpp
index 12ce20ef09..b98ed8b443 100644
--- a/src/corelib/json/qjsonwriter.cpp
+++ b/src/corelib/json/qjsonwriter.cpp
@@ -128,9 +128,15 @@ static void valueToJson(const QJsonPrivate::Base *b, const QJsonPrivate::Value &
     case QJsonValue::Bool:
         json += v.toBoolean() ? "true" : "false";
         break;
+    case QJsonValue::LongLong:
+        json += QByteArray::number(v.toLongLong(b));
+        break;
     case QJsonValue::Double: {
         const double d = v.toDouble(b);
-        if (qIsFinite(d)) { // +2 to format to ensure the expected precision
+        if (double(qint64(d)) == d) {
+            // Write integers as integers:
+            json += QByteArray::number(qint64(d));
+        } else if (qIsFinite(d)) { // +2 to format to ensure the expected precision
             const double abs = std::abs(d);
             json += QByteArray::number(d, abs == static_cast<quint64>(abs) ? 'f' : 'g', QLocale::FloatingPointShortest);
         } else {
diff --git a/tests/auto/corelib/json/tst_qtjson.cpp b/tests/auto/corelib/json/tst_qtjson.cpp
index b215364f0e..613790f00e 100644
--- a/tests/auto/corelib/json/tst_qtjson.cpp
+++ b/tests/auto/corelib/json/tst_qtjson.cpp
@@ -200,24 +200,28 @@ void tst_QtJson::testNumbers()
             0,
             -1,
             1,
+            (1<<25),
             (1<<26),
             (1<<27),
             (1<<28),
+            -(1<<25),
             -(1<<26),
             -(1<<27),
             -(1<<28),
             (1<<26) - 1,
             (1<<27) - 1,
             (1<<28) - 1,
+            (1<<29) - 1,
             -((1<<26) - 1),
             -((1<<27) - 1),
-            -((1<<28) - 1)
+            -((1<<28) - 1),
+            -((1<<29) - 1)
         };
         int n = sizeof(numbers)/sizeof(int);
 
         QJsonArray array;
         for (int i = 0; i < n; ++i)
-            array.append((double)numbers[i]);
+            array.append(numbers[i]);
 
         QByteArray serialized = QJsonDocument(array).toJson();
         QJsonDocument json = QJsonDocument::fromJson(serialized);
@@ -226,9 +230,9 @@ void tst_QtJson::testNumbers()
         QCOMPARE(array.size(), array2.size());
         for (int i = 0; i < array.size(); ++i) {
             QCOMPARE(array.at(i).type(), QJsonValue::Double);
-            QCOMPARE(array.at(i).toDouble(), (double)numbers[i]);
+            QCOMPARE(array.at(i).toInt(), numbers[i]);
             QCOMPARE(array2.at(i).type(), QJsonValue::Double);
-            QCOMPARE(array2.at(i).toDouble(), (double)numbers[i]);
+            QCOMPARE(array2.at(i).toInt(), numbers[i]);
         }
     }
 
@@ -246,6 +250,9 @@ void tst_QtJson::testNumbers()
             (1ll<<54) - 1,
             (1ll<<55) - 1,
             (1ll<<56) - 1,
+            (1ll<<57) - 1,
+            (1ll<<58) - 1,
+            (1ll<<59) + 1001,
             -((1ll<<54) - 1),
             -((1ll<<55) - 1),
             -((1ll<<56) - 1)
@@ -254,7 +261,7 @@ void tst_QtJson::testNumbers()
 
         QJsonArray array;
         for (int i = 0; i < n; ++i)
-            array.append((double)numbers[i]);
+            array.append(QJsonValue(numbers[i]));
 
         QByteArray serialized = QJsonDocument(array).toJson();
         QJsonDocument json = QJsonDocument::fromJson(serialized);
@@ -262,10 +269,10 @@ void tst_QtJson::testNumbers()
 
         QCOMPARE(array.size(), array2.size());
         for (int i = 0; i < array.size(); ++i) {
-            QCOMPARE(array.at(i).type(), QJsonValue::Double);
-            QCOMPARE(array.at(i).toDouble(), (double)numbers[i]);
-            QCOMPARE(array2.at(i).type(), QJsonValue::Double);
-            QCOMPARE(array2.at(i).toDouble(), (double)numbers[i]);
+            QVERIFY(array.at(i).isNumber());
+            QCOMPARE(array.at(i).toLongLong(), numbers[i]);
+            QVERIFY(array2.at(i).isNumber());
+            QCOMPARE(array2.at(i).toLongLong(), numbers[i]);
         }
     }
 
@@ -397,7 +404,7 @@ void tst_QtJson::testNumbers_4()
             "    9007199254740992,\n"
             "    -9007199254740992,\n"
             "    9223372036854776000,\n"
-            "    -9223372036854776000,\n"
+            "    -9223372036854775808,\n"
             "    18446744073709552000,\n"
             "    -18446744073709552000\n"
             "]\n";
