diff --git a/src/layouts/qquickgridlayoutengine.cpp b/src/layouts/qquickgridlayoutengine.cpp
index bacfd965bbef56085abcd5d56b76d07fea728a78..7f65d0d5bf56c46dc92f36426d59e04415830c9f 100644
--- a/src/layouts/qquickgridlayoutengine.cpp
+++ b/src/layouts/qquickgridlayoutengine.cpp
@@ -98,14 +98,62 @@ static inline void combineHints(qreal &current, qreal fallbackHint)
         current = fallbackHint;
 }
 
+static inline void combineSize(QSizeF &result, const QSizeF &fallbackSize)
+{
+    combineHints(result.rwidth(), fallbackSize.width());
+    combineHints(result.rheight(), fallbackSize.height());
+}
+
+static inline void combineImplicitHints(QQuickLayoutAttached *info, Qt::SizeHint which, QSizeF *size)
+{
+    if (!info) return;
+
+    Q_ASSERT(which == Qt::MinimumSize || which == Qt::MaximumSize);
+
+    const QSizeF constraint(which == Qt::MinimumSize
+                            ? QSizeF(info->minimumWidth(), info->minimumHeight())
+                            : QSizeF(info->maximumWidth(), info->maximumHeight()));
+
+    if (!info->isExtentExplicitlySet(Qt::Horizontal, which))
+        combineHints(size->rwidth(),  constraint.width());
+    if (!info->isExtentExplicitlySet(Qt::Vertical, which))
+        combineHints(size->rheight(), constraint.height());
+}
+
 /*!
     \internal
     Note: Can potentially return the attached QQuickLayoutAttached object through \a attachedInfo.
 
     It is like this is because it enables it to be reused.
+
+    The goal of this function is to return the effective minimum, preferred and maximum size hints
+    that the layout will use for this item.
+    This function takes care of gathering all explicitly set size hints, normalizes them so
+    that min < pref < max.
+    Further, the hints _not_explicitly_ set will then be initialized with the implicit size hints,
+    which is usually derived from the content of the layouts (or items).
+
+    The following table illustrates the preference of the properties used for measuring layout
+    items. If present, the USER properties will be preferred. If USER properties are not present,
+    the HINT properties will be preferred. Finally, the FALLBACK properties will be used as an
+    ultimate fallback.
+
+    Note that one can query if the value of Layout.minimumWidth or Layout.maximumWidth has been
+    explicitly or implicitly set with QQuickLayoutAttached::isExtentExplicitlySet(). This
+    determines if it should be used as a USER or as a HINT value.
+
+
+                 | *Minimum*            | *Preferred*           | *Maximum*                |
++----------------+----------------------+-----------------------+--------------------------+
+|USER (explicit) | Layout.minimumWidth  | Layout.preferredWidth | Layout.maximumWidth      |
+|HINT (implicit) | Layout.minimumWidth  | implicitWidth         | Layout.maximumWidth      |
+|FALLBACK        | 0                    | width                 | Number.POSITIVE_INFINITY |
++----------------+----------------------+-----------------------+--------------------------+
  */
 void QQuickGridLayoutItem::effectiveSizeHints_helper(QQuickItem *item, QSizeF *cachedSizeHints, QQuickLayoutAttached **attachedInfo, bool useFallbackToWidthOrHeight)
 {
+    for (int i = 0; i < Qt::NSizeHints; ++i)
+        cachedSizeHints[i] = QSizeF();
     QQuickLayoutAttached *info = attachedLayoutObject(item, false);
     // First, retrieve the user-specified hints from the attached "Layout." properties
     if (info) {
@@ -123,16 +171,16 @@ void QQuickGridLayoutItem::effectiveSizeHints_helper(QQuickItem *item, QSizeF *c
         for (int i = 0; i < NSizes; ++i) {
             SizeGetter getter = horGetters.call[i];
             Q_ASSERT(getter);
-            cachedSizeHints[i].setWidth((info->*getter)());
+
+            if (info->isExtentExplicitlySet(Qt::Horizontal, (Qt::SizeHint)i))
+                cachedSizeHints[i].setWidth((info->*getter)());
+
             getter = verGetters.call[i];
             Q_ASSERT(getter);
-            cachedSizeHints[i].setHeight((info->*getter)());
+            if (info->isExtentExplicitlySet(Qt::Vertical, (Qt::SizeHint)i))
+                cachedSizeHints[i].setHeight((info->*getter)());
         }
-    } else {
-        for (int i = 0; i < NSizes; ++i)
-            cachedSizeHints[i] = QSize();
     }
-    cachedSizeHints[Qt::MinimumDescent] = QSize();  //### FIXME when baseline support is added
 
     QSizeF &minS = cachedSizeHints[Qt::MinimumSize];
     QSizeF &prefS = cachedSizeHints[Qt::PreferredSize];
@@ -144,23 +192,21 @@ void QQuickGridLayoutItem::effectiveSizeHints_helper(QQuickItem *item, QSizeF *c
     // to:   [10, 10, 60]
     normalizeHints(minS.rwidth(), prefS.rwidth(), maxS.rwidth(), descentS.rwidth());
     normalizeHints(minS.rheight(), prefS.rheight(), maxS.rheight(), descentS.rheight());
-/*
-  The following table illustrates the preference of the properties used for measuring layout
-  items. If present, the USER properties will be preferred. If USER properties are not present,
-  the HINT 1 properties will be preferred. Finally, the HINT 2 properties will be used as an
-  ultimate fallback.
-
-       | USER                           | HINT 1            | HINT 2
-  -----+--------------------------------+-------------------+-------
-  MIN  | Layout.minimumWidth            |                   | 0
-  PREF | Layout.preferredWidth          | implicitWidth     | width
-  MAX  | Layout.maximumWidth            |                   | 1000000000 (-1)
-  -----+--------------------------------+-------------------+--------
-Fixed    | Layout.fillWidth               | Expanding if layout, Fixed if item |
-
-*/
+
+    // All explicit values gathered, now continue to gather the implicit sizes
+
+    //--- GATHER MAXIMUM SIZE HINTS ---
+    combineImplicitHints(info, Qt::MaximumSize, &maxS);
+    combineSize(maxS, QSizeF(std::numeric_limits<qreal>::infinity(), std::numeric_limits<qreal>::infinity()));
+    // implicit max or min sizes should not limit an explicitly set preferred size
+    expandSize(maxS, prefS);
+    expandSize(maxS, minS);
+
     //--- GATHER MINIMUM SIZE HINTS ---
-    // They are always 0
+    combineImplicitHints(info, Qt::MinimumSize, &minS);
+    expandSize(minS, QSizeF(0,0));
+    boundSize(minS, prefS);
+    boundSize(minS, maxS);
 
     //--- GATHER PREFERRED SIZE HINTS ---
     // First, from implicitWidth/Height
@@ -203,17 +249,12 @@ Fixed    | Layout.fillWidth               | Expanding if layout, Fixed if item |
             item->blockSignals(false);
         }
     }
-    //--- GATHER MAXIMUM SIZE HINTS ---
-    combineHints(cachedSizeHints[Qt::MaximumSize].rwidth(), std::numeric_limits<qreal>::infinity());
-    combineHints(cachedSizeHints[Qt::MaximumSize].rheight(), std::numeric_limits<qreal>::infinity());
 
     //--- GATHER DESCENT
     // ### Not implemented
 
 
     // Normalize again after the implicit hints have been gathered
-    expandSize(minS, QSizeF(0,0));
-    boundSize(minS, maxS);
     expandSize(prefS, minS);
     boundSize(prefS, maxS);
 
diff --git a/src/layouts/qquicklayout_p.h b/src/layouts/qquicklayout_p.h
index 8a334677a781d77ec2e4548b39478e18308ec0a3..0239739a649e90c5b17f963b5f61169bc11a0d18 100644
--- a/src/layouts/qquicklayout_p.h
+++ b/src/layouts/qquicklayout_p.h
@@ -175,6 +175,22 @@ public:
 
     qreal sizeHint(Qt::SizeHint which, Qt::Orientation orientation) const;
 
+    bool isExtentExplicitlySet(Qt::Orientation o, Qt::SizeHint whichSize) const
+    {
+        switch (whichSize) {
+        case Qt::MinimumSize:
+            return o == Qt::Horizontal ? m_isMinimumWidthSet : m_isMinimumHeightSet;
+        case Qt::MaximumSize:
+            return o == Qt::Horizontal ? m_isMaximumWidthSet : m_isMaximumHeightSet;
+        case Qt::PreferredSize:
+            return true;            // Layout.preferredWidth is always explicitly set
+        case Qt::MinimumDescent:    // Not supported
+        case Qt::NSizeHints:
+            return false;
+        }
+        return false;
+    }
+
 signals:
     void minimumWidthChanged();
     void minimumHeightChanged();
diff --git a/tests/auto/controls/data/tst_rowlayout.qml b/tests/auto/controls/data/tst_rowlayout.qml
index 458a2885f2604a453faf400f039d904982e978a2..e92dad47efec3eee7d36588386034eb4a1c7ab95 100644
--- a/tests/auto/controls/data/tst_rowlayout.qml
+++ b/tests/auto/controls/data/tst_rowlayout.qml
@@ -459,6 +459,12 @@ Item {
                     { tag: "propagateMaximumWidth",    layoutHints: [10, 20, -1], childHints: [11, 21, 30], expected:[10, 20, 30]},
                     { tag: "propagateAll",             layoutHints: [-1, -1, -1], childHints: [10, 20, 30], expected:[10, 20, 30]},
                     { tag: "propagateCrazy",           layoutHints: [-1, -1, -1], childHints: [40, 21, 30], expected:[30, 30, 30]},
+                    { tag: "expandMinToExplicitPref",  layoutHints: [-1,  1, -1], childHints: [11, 21, 31], expected:[ 1,  1, 31]},
+                    { tag: "expandMaxToExplicitPref",  layoutHints: [-1, 99, -1], childHints: [11, 21, 31], expected:[11, 99, 99]},
+                    { tag: "expandAllToExplicitMin",   layoutHints: [99, -1, -1], childHints: [11, 21, 31], expected:[99, 99, 99]},
+                    { tag: "expandPrefToExplicitMin",  layoutHints: [24, -1, -1], childHints: [11, 21, 31], expected:[24, 24, 31]},
+                    { tag: "boundPrefToExplicitMax",   layoutHints: [-1, -1, 19], childHints: [11, 21, 31], expected:[11, 19, 19]},
+                    { tag: "boundAllToExplicitMax",    layoutHints: [-1, -1,  9], childHints: [11, 21, 31], expected:[ 9,  9,  9]},
                     ];
         }
 
@@ -468,22 +474,21 @@ Item {
 
         function test_sizeHint(data) {
             var layout = layout_sizeHint_Component.createObject(container)
-            layout.Layout.minimumWidth = data.layoutHints[0]
-            layout.Layout.preferredWidth = data.layoutHints[1]
-            layout.Layout.maximumWidth = data.layoutHints[2]
 
-            var child = layout.children[0].children[0]
+            var grid = layout.children[0]
+            grid.Layout.minimumWidth = data.layoutHints[0]
+            grid.Layout.preferredWidth = data.layoutHints[1]
+            grid.Layout.maximumWidth = data.layoutHints[2]
+
+            var child = grid.children[0]
             if (data.implicitWidth !== undefined) {
                 child.implicitWidth = data.implicitWidth
             }
-
             child.Layout.minimumWidth = data.childHints[0]
             child.Layout.preferredWidth = data.childHints[1]
             child.Layout.maximumWidth = data.childHints[2]
 
-            var grid = layout.children[0]
-            var preferredWidth = layout.Layout.preferredWidth >= 0 ? layout.Layout.preferredWidth : layout.implicitWidth
-            var effectiveSizeHintResult = [layout.Layout.minimumWidth, preferredWidth, layout.Layout.maximumWidth]
+            var effectiveSizeHintResult = [layout.Layout.minimumWidth, layout.implicitWidth, layout.Layout.maximumWidth]
             compare(effectiveSizeHintResult, data.expected)
             layout.destroy()
         }