diff --git a/src/plot_api/plot_api.js b/src/plot_api/plot_api.js
index eb8323aca96..51d5bf5c514 100644
--- a/src/plot_api/plot_api.js
+++ b/src/plot_api/plot_api.js
@@ -153,6 +153,8 @@ exports.plot = function(gd, data, layout, config) {
 
     var fullLayout = gd._fullLayout;
 
+    var hasCartesian = fullLayout._has('cartesian');
+
     // Legacy polar plots
     if(!fullLayout._has('polar') && data && data[0] && data[0].r) {
         Lib.log('Legacy polar charts are deprecated!');
@@ -426,16 +428,18 @@ exports.plot = function(gd, data, layout, config) {
         addFrames,
         drawFramework,
         marginPushers,
-        marginPushersAgain,
-        positionAndAutorange,
-        subroutines.layoutStyles,
-        drawAxes,
+        marginPushersAgain
+    ];
+    if(hasCartesian) seq.push(positionAndAutorange);
+    seq.push(subroutines.layoutStyles);
+    if(hasCartesian) seq.push(drawAxes);
+    seq.push(
         drawData,
         finalDraw,
         initInteractions,
         Plots.rehover,
         Plots.previousPromises
-    ];
+    );
 
     // even if everything we did was synchronous, return a promise
     // so that the caller doesn't care which route we took
@@ -2611,7 +2615,7 @@ function getDiffFlags(oldContainer, newContainer, outerparts, opts) {
     }
 
     for(key in newContainer) {
-        if(!(key in oldContainer)) {
+        if(!(key in oldContainer || key.charAt(0) === '_' || typeof newContainer[key] === 'function')) {
             valObject = getValObject(outerparts.concat(key));
 
             if(valObjectCanBeDataArray(valObject) && Array.isArray(newContainer[key])) {
diff --git a/src/plots/cartesian/index.js b/src/plots/cartesian/index.js
index 84d728253bc..89a0e850f00 100644
--- a/src/plots/cartesian/index.js
+++ b/src/plots/cartesian/index.js
@@ -287,6 +287,7 @@ exports.clean = function(newFullData, newFullLayout, oldFullData, oldFullLayout)
     if(hadCartesian && !hasCartesian) {
         purgeSubplotLayers(oldFullLayout._cartesianlayer.selectAll('.subplot'), oldFullLayout);
         oldFullLayout._defs.selectAll('.axesclip').remove();
+        delete oldFullLayout._axisConstraintGroups;
     }
     // otherwise look for subplots we need to remove
     else if(oldSubplotList.cartesian) {
diff --git a/test/jasmine/tests/plot_api_test.js b/test/jasmine/tests/plot_api_test.js
index 085f9fbc961..8af0b1e3820 100644
--- a/test/jasmine/tests/plot_api_test.js
+++ b/test/jasmine/tests/plot_api_test.js
@@ -1261,6 +1261,21 @@ describe('Test plot api', function() {
             .catch(fail)
             .then(done);
         });
+
+        it('can drop Cartesian while constraints are active', function(done) {
+            Plotly.newPlot(gd, [{x: [1, 2, 3], y: [1, 3, 2], z: [2, 3, 1]}], {xaxis: {scaleanchor: 'y'}})
+            .then(function() {
+                expect(gd._fullLayout._axisConstraintGroups).toBeDefined();
+                expect(gd._fullLayout.scene !== undefined).toBe(false);
+                return Plotly.restyle(gd, {type: 'scatter3d'});
+            })
+            .then(function() {
+                expect(gd._fullLayout._axisConstraintGroups).toBeUndefined();
+                expect(gd._fullLayout.scene !== undefined).toBe(true);
+            })
+            .catch(fail)
+            .then(done);
+        });
     });
 
     describe('Plotly.deleteTraces', function() {