diff --git a/modules/core/src/matrix.cpp b/modules/core/src/matrix.cpp
index 8161efc57d..c0ad8c4ecc 100644
--- a/modules/core/src/matrix.cpp
+++ b/modules/core/src/matrix.cpp
@@ -4257,7 +4257,45 @@ Mat Mat::reshape(int _cn, int _newndims, const int* _newsz) const
             return reshape(_cn, _newsz[0]);
     }
 
-    CV_Error(CV_StsNotImplemented, "");
+    if (isContinuous())
+    {
+        CV_Assert(_cn >= 0 && _newndims > 0 && _newndims <= CV_MAX_DIM && _newsz);
+
+        if (_cn == 0)
+            _cn = this->channels();
+        else
+            CV_Assert(_cn <= CV_CN_MAX);
+
+        size_t total_elem1_ref = this->total() * this->channels();
+        size_t total_elem1 = _cn;
+
+        AutoBuffer<int, 4> newsz_buf( (size_t)_newndims );
+
+        for (int i = 0; i < _newndims; i++)
+        {
+            CV_Assert(_newsz[i] >= 0);
+
+            if (_newsz[i] > 0)
+                newsz_buf[i] = _newsz[i];
+            else if (i < dims)
+                newsz_buf[i] = this->size[i];
+            else
+                CV_Error(CV_StsOutOfRange, "Copy dimension (which has zero size) is not present in source matrix");
+
+            total_elem1 *= (size_t)newsz_buf[i];
+        }
+
+        if (total_elem1 != total_elem1_ref)
+            CV_Error(CV_StsUnmatchedSizes, "Requested and source matrices have different count of elements");
+
+        Mat hdr = *this;
+        hdr.flags = (hdr.flags & ~CV_MAT_CN_MASK) | ((_cn-1) << CV_CN_SHIFT);
+        setSize(hdr, _newndims, (int*)newsz_buf, NULL, true);
+
+        return hdr;
+    }
+
+    CV_Error(CV_StsNotImplemented, "Reshaping of n-dimensional non-continuous matrices is not supported yet");
     // TBD
     return Mat();
 }
diff --git a/modules/core/src/umatrix.cpp b/modules/core/src/umatrix.cpp
index 48aa86635d..f378e36113 100644
--- a/modules/core/src/umatrix.cpp
+++ b/modules/core/src/umatrix.cpp
@@ -574,12 +574,49 @@ UMat UMat::reshape(int _cn, int _newndims, const int* _newsz) const
             return reshape(_cn, _newsz[0]);
     }
 
-    CV_Error(CV_StsNotImplemented, "");
+    if (isContinuous())
+    {
+        CV_Assert(_cn >= 0 && _newndims > 0 && _newndims <= CV_MAX_DIM && _newsz);
+
+        if (_cn == 0)
+            _cn = this->channels();
+        else
+            CV_Assert(_cn <= CV_CN_MAX);
+
+        size_t total_elem1_ref = this->total() * this->channels();
+        size_t total_elem1 = _cn;
+
+        AutoBuffer<int, 4> newsz_buf( (size_t)_newndims );
+
+        for (int i = 0; i < _newndims; i++)
+        {
+            CV_Assert(_newsz[i] >= 0);
+
+            if (_newsz[i] > 0)
+                newsz_buf[i] = _newsz[i];
+            else if (i < dims)
+                newsz_buf[i] = this->size[i];
+            else
+                CV_Error(CV_StsOutOfRange, "Copy dimension (which has zero size) is not present in source matrix");
+
+            total_elem1 *= (size_t)newsz_buf[i];
+        }
+
+        if (total_elem1 != total_elem1_ref)
+            CV_Error(CV_StsUnmatchedSizes, "Requested and source matrices have different count of elements");
+
+        UMat hdr = *this;
+        hdr.flags = (hdr.flags & ~CV_MAT_CN_MASK) | ((_cn-1) << CV_CN_SHIFT);
+        setSize(hdr, _newndims, (int*)newsz_buf, NULL, true);
+
+        return hdr;
+    }
+
+    CV_Error(CV_StsNotImplemented, "Reshaping of n-dimensional non-continuous matrices is not supported yet");
     // TBD
     return UMat();
 }
 
-
 Mat UMat::getMat(int accessFlags) const
 {
     if(!u)
diff --git a/modules/core/test/test_mat.cpp b/modules/core/test/test_mat.cpp
index e2d4e8a4bf..2344df28a5 100644
--- a/modules/core/test/test_mat.cpp
+++ b/modules/core/test/test_mat.cpp
@@ -1194,6 +1194,73 @@ TEST(Core_Mat, reshape_1942)
     ASSERT_EQ(1, cn);
 }
 
+static void check_ndim_shape(const cv::Mat &mat, int cn, int ndims, const int *sizes)
+{
+    EXPECT_EQ(mat.channels(), cn);
+    EXPECT_EQ(mat.dims, ndims);
+
+    if (mat.dims != ndims)
+        return;
+
+    for (int i = 0; i < ndims; i++)
+        EXPECT_EQ(mat.size[i], sizes[i]);
+}
+
+TEST(Core_Mat, reshape_ndims_2)
+{
+    const cv::Mat A(8, 16, CV_8UC3);
+    cv::Mat B;
+
+    {
+        int new_sizes_mask[] = { 0, 3, 4, 4 };
+        int new_sizes_real[] = { 8, 3, 4, 4 };
+        ASSERT_NO_THROW(B = A.reshape(1, 4, new_sizes_mask));
+        check_ndim_shape(B, 1, 4, new_sizes_real);
+    }
+    {
+        int new_sizes[] = { 16, 8 };
+        ASSERT_NO_THROW(B = A.reshape(0, 2, new_sizes));
+        check_ndim_shape(B, 3, 2, new_sizes);
+        EXPECT_EQ(B.rows, new_sizes[0]);
+        EXPECT_EQ(B.cols, new_sizes[1]);
+    }
+    {
+        int new_sizes[] = { 2, 5, 1, 3 };
+        cv::Mat A_sliced = A(cv::Range::all(), cv::Range(0, 15));
+        ASSERT_ANY_THROW(A_sliced.reshape(4, 4, new_sizes));
+    }
+}
+
+TEST(Core_Mat, reshape_ndims_4)
+{
+    const int sizes[] = { 2, 6, 4, 12 };
+    const cv::Mat A(4, sizes, CV_8UC3);
+    cv::Mat B;
+
+    {
+        int new_sizes_mask[] = { 0, 864 };
+        int new_sizes_real[] = { 2, 864 };
+        ASSERT_NO_THROW(B = A.reshape(1, 2, new_sizes_mask));
+        check_ndim_shape(B, 1, 2, new_sizes_real);
+        EXPECT_EQ(B.rows, new_sizes_real[0]);
+        EXPECT_EQ(B.cols, new_sizes_real[1]);
+    }
+    {
+        int new_sizes_mask[] = { 4, 0, 0, 2, 3 };
+        int new_sizes_real[] = { 4, 6, 4, 2, 3 };
+        ASSERT_NO_THROW(B = A.reshape(0, 5, new_sizes_mask));
+        check_ndim_shape(B, 3, 5, new_sizes_real);
+    }
+    {
+        int new_sizes_mask[] = { 1, 1 };
+        ASSERT_ANY_THROW(A.reshape(0, 2, new_sizes_mask));
+    }
+    {
+        int new_sizes_mask[] = { 4, 6, 3, 3, 0 };
+        ASSERT_ANY_THROW(A.reshape(0, 5, new_sizes_mask));
+    }
+}
+
 TEST(Core_Mat, push_back)
 {
     Mat a = (Mat_<float>(1,2) << 3.4884074f, 1.4159607f);
diff --git a/modules/core/test/test_umat.cpp b/modules/core/test/test_umat.cpp
index 0e25b6ba9a..c4cdf14ee6 100644
--- a/modules/core/test/test_umat.cpp
+++ b/modules/core/test/test_umat.cpp
@@ -350,6 +350,73 @@ TEST_P(UMatTestReshape, DISABLED_reshape)
 
 INSTANTIATE_TEST_CASE_P(UMat, UMatTestReshape, Combine(OCL_ALL_DEPTHS, OCL_ALL_CHANNELS, UMAT_TEST_SIZES, Bool() ));
 
+static void check_ndim_shape(const cv::UMat &mat, int cn, int ndims, const int *sizes)
+{
+    EXPECT_EQ(mat.channels(), cn);
+    EXPECT_EQ(mat.dims, ndims);
+
+    if (mat.dims != ndims)
+        return;
+
+    for (int i = 0; i < ndims; i++)
+        EXPECT_EQ(mat.size[i], sizes[i]);
+}
+
+TEST(UMatTestReshape, reshape_ndims_2)
+{
+    const cv::UMat A(8, 16, CV_8UC3);
+    cv::UMat B;
+
+    {
+        int new_sizes_mask[] = { 0, 3, 4, 4 };
+        int new_sizes_real[] = { 8, 3, 4, 4 };
+        ASSERT_NO_THROW(B = A.reshape(1, 4, new_sizes_mask));
+        check_ndim_shape(B, 1, 4, new_sizes_real);
+    }
+    {
+        int new_sizes[] = { 16, 8 };
+        ASSERT_NO_THROW(B = A.reshape(0, 2, new_sizes));
+        check_ndim_shape(B, 3, 2, new_sizes);
+        EXPECT_EQ(B.rows, new_sizes[0]);
+        EXPECT_EQ(B.cols, new_sizes[1]);
+    }
+    {
+        int new_sizes[] = { 2, 5, 1, 3 };
+        cv::UMat A_sliced = A(cv::Range::all(), cv::Range(0, 15));
+        ASSERT_ANY_THROW(A_sliced.reshape(4, 4, new_sizes));
+    }
+}
+
+TEST(UMatTestReshape, reshape_ndims_4)
+{
+    const int sizes[] = { 2, 6, 4, 12 };
+    const cv::UMat A(4, sizes, CV_8UC3);
+    cv::UMat B;
+
+    {
+        int new_sizes_mask[] = { 0, 864 };
+        int new_sizes_real[] = { 2, 864 };
+        ASSERT_NO_THROW(B = A.reshape(1, 2, new_sizes_mask));
+        check_ndim_shape(B, 1, 2, new_sizes_real);
+        EXPECT_EQ(B.rows, new_sizes_real[0]);
+        EXPECT_EQ(B.cols, new_sizes_real[1]);
+    }
+    {
+        int new_sizes_mask[] = { 4, 0, 0, 2, 3 };
+        int new_sizes_real[] = { 4, 6, 4, 2, 3 };
+        ASSERT_NO_THROW(B = A.reshape(0, 5, new_sizes_mask));
+        check_ndim_shape(B, 3, 5, new_sizes_real);
+    }
+    {
+        int new_sizes_mask[] = { 1, 1 };
+        ASSERT_ANY_THROW(A.reshape(0, 2, new_sizes_mask));
+    }
+    {
+        int new_sizes_mask[] = { 4, 6, 3, 3, 0 };
+        ASSERT_ANY_THROW(A.reshape(0, 5, new_sizes_mask));
+    }
+}
+
 ////////////////////////////////////////////////////////////////// ROI testing ///////////////////////////////////////////////////////////////
 
 PARAM_TEST_CASE(UMatTestRoi, int, int, Size)