diff --git a/sklearn/model_selection/_search.py b/sklearn/model_selection/_search.py
index b2345398aa92ee5657057582958898d3c615ef27..82516f1e6ba4a76eb1f361a5724e69c60718c52a 100644
--- a/sklearn/model_selection/_search.py
+++ b/sklearn/model_selection/_search.py
@@ -30,6 +30,7 @@ from ..externals import six
 from ..utils import check_random_state
 from ..utils.fixes import sp_version
 from ..utils.fixes import rankdata
+from ..utils.fixes import MaskedArray
 from ..utils.random import sample_without_replacement
 from ..utils.validation import indexable, check_is_fitted
 from ..utils.metaestimators import if_delegate_has_method
@@ -611,10 +612,12 @@ class BaseSearchCV(six.with_metaclass(ABCMeta, BaseEstimator,
         best_index = np.flatnonzero(results["rank_test_score"] == 1)[0]
         best_parameters = candidate_params[best_index]
 
-        # Use one np.MaskedArray and mask all the places where the param is not
+        # Use one MaskedArray and mask all the places where the param is not
         # applicable for that candidate. Use defaultdict as each candidate may
         # not contain all the params
-        param_results = defaultdict(partial(np.ma.masked_all, (n_candidates,),
+        param_results = defaultdict(partial(MaskedArray,
+                                            np.empty(n_candidates,),
+                                            mask=True,
                                             dtype=object))
         for cand_i, params in enumerate(candidate_params):
             for name, value in params.items():
diff --git a/sklearn/model_selection/tests/test_search.py b/sklearn/model_selection/tests/test_search.py
index 30daacf4c42fb44eb818113104447b9e1d32521e..36e6965a11974c4a562a21d2f03858429e3e9547 100644
--- a/sklearn/model_selection/tests/test_search.py
+++ b/sklearn/model_selection/tests/test_search.py
@@ -940,12 +940,16 @@ def test_pickle():
     clf = MockClassifier()
     grid_search = GridSearchCV(clf, {'foo_param': [1, 2, 3]}, refit=True)
     grid_search.fit(X, y)
-    pickle.dumps(grid_search)  # smoke test
+    grid_search_pickled = pickle.loads(pickle.dumps(grid_search))
+    assert_array_almost_equal(grid_search.predict(X),
+                              grid_search_pickled.predict(X))
 
     random_search = RandomizedSearchCV(clf, {'foo_param': [1, 2, 3]},
                                        refit=True, n_iter=3)
     random_search.fit(X, y)
-    pickle.dumps(random_search)  # smoke test
+    random_search_pickled = pickle.loads(pickle.dumps(random_search))
+    assert_array_almost_equal(random_search.predict(X),
+                              random_search_pickled.predict(X))
 
 
 def test_grid_search_with_multioutput_data():
diff --git a/sklearn/utils/fixes.py b/sklearn/utils/fixes.py
index aa27bf5434aeb8dd24bc929f2db0b42c754d907a..682ab7733c77a2839acbde7f6ef6e1d2769ddaf3 100644
--- a/sklearn/utils/fixes.py
+++ b/sklearn/utils/fixes.py
@@ -401,3 +401,21 @@ if sp_version < (0, 13, 0):
         return .5 * (count[dense] + count[dense - 1] + 1)
 else:
     from scipy.stats import rankdata
+
+
+if np_version < (1, 12, 0):
+    class MaskedArray(np.ma.MaskedArray):
+        # Before numpy 1.12, np.ma.MaskedArray object is not picklable
+        # This fix is needed to make our model_selection.GridSearchCV
+        # picklable as the ``cv_results_`` param uses MaskedArray
+        def __getstate__(self):
+            """Return the internal state of the masked array, for pickling
+            purposes.
+
+            """
+            cf = 'CF'[self.flags.fnc]
+            data_state = super(np.ma.MaskedArray, self).__reduce__()[2]
+            return data_state + (np.ma.getmaskarray(self).tostring(cf),
+                                 self._fill_value)
+else:
+    from numpy.ma import MaskedArray    # noqa
diff --git a/sklearn/utils/tests/test_fixes.py b/sklearn/utils/tests/test_fixes.py
index f5817f246b908a5037daa8934549f95c7cc8ae73..ef1110bfc4eedd1a53fce08dac9f18faaca8628e 100644
--- a/sklearn/utils/tests/test_fixes.py
+++ b/sklearn/utils/tests/test_fixes.py
@@ -3,13 +3,19 @@
 #          Lars Buitinck
 # License: BSD 3 clause
 
+import pickle
 import numpy as np
 
-from numpy.testing import (assert_almost_equal,
-                           assert_array_almost_equal)
+from sklearn.utils.testing import assert_equal
+from sklearn.utils.testing import assert_false
+from sklearn.utils.testing import assert_true
+from sklearn.utils.testing import assert_almost_equal
+from sklearn.utils.testing import assert_array_equal
+from sklearn.utils.testing import assert_array_almost_equal
+
 from sklearn.utils.fixes import divide, expit
 from sklearn.utils.fixes import astype
-from sklearn.utils.testing import assert_equal, assert_false, assert_true
+from sklearn.utils.fixes import MaskedArray
 
 
 def test_expit():
@@ -50,3 +56,13 @@ def test_astype_copy_memory():
 
     e_int32 = astype(a_int32, dtype=np.int32)
     assert_false(np.may_share_memory(e_int32, a_int32))
+
+
+def test_masked_array_obj_dtype_pickleable():
+    marr = MaskedArray([1, None, 'a'], dtype=object)
+
+    for mask in (True, False, [0, 1, 0]):
+        marr.mask = mask
+        marr_pickled = pickle.loads(pickle.dumps(marr))
+        assert_array_equal(marr.data, marr_pickled.data)
+        assert_array_equal(marr.mask, marr_pickled.mask)