diff --git a/modules/core/misc/python/pyopencv_core.hpp b/modules/core/misc/python/pyopencv_core.hpp
index 9017a5becc..8f7abb08da 100644
--- a/modules/core/misc/python/pyopencv_core.hpp
+++ b/modules/core/misc/python/pyopencv_core.hpp
@@ -15,16 +15,10 @@ CV_PY_TO_CLASS(cuda::HostMem);
 CV_PY_TO_CLASS_PTR(cuda::GpuMat);
 CV_PY_TO_CLASS_PTR(cuda::GpuMat::Allocator);
 
-CV_PY_TO_ENUM(cuda::Event::CreateFlags);
-CV_PY_TO_ENUM(cuda::HostMem::AllocType);
-CV_PY_TO_ENUM(cuda::FeatureSet);
-
 CV_PY_FROM_CLASS(cuda::GpuMat);
 CV_PY_FROM_CLASS(cuda::Stream);
 CV_PY_FROM_CLASS(cuda::HostMem);
 
 CV_PY_FROM_CLASS_PTR(cuda::GpuMat::Allocator);
 
-CV_PY_FROM_ENUM(cuda::DeviceInfo::ComputeMode);
-
 #endif
diff --git a/modules/core/misc/python/pyopencv_umat.hpp b/modules/core/misc/python/pyopencv_umat.hpp
index 003dce04fc..697adaf202 100644
--- a/modules/core/misc/python/pyopencv_umat.hpp
+++ b/modules/core/misc/python/pyopencv_umat.hpp
@@ -6,9 +6,6 @@ typedef std::vector<Range> vector_Range;
 
 CV_PY_TO_CLASS(UMat);
 CV_PY_FROM_CLASS(UMat);
-CV_PY_TO_ENUM(UMatUsageFlags);
-CV_PY_FROM_ENUM(AccessFlag);
-CV_PY_TO_ENUM(AccessFlag);
 
 static bool cv_mappable_to(const Ptr<Mat>& src, Ptr<UMat>& dst)
 {
diff --git a/modules/features2d/misc/python/pyopencv_features2d.hpp b/modules/features2d/misc/python/pyopencv_features2d.hpp
index ae43995eff..2bcf403708 100644
--- a/modules/features2d/misc/python/pyopencv_features2d.hpp
+++ b/modules/features2d/misc/python/pyopencv_features2d.hpp
@@ -6,19 +6,4 @@ typedef FastFeatureDetector::DetectorType FastFeatureDetector_DetectorType;
 typedef DescriptorMatcher::MatcherType DescriptorMatcher_MatcherType;
 typedef KAZE::DiffusivityType KAZE_DiffusivityType;
 typedef ORB::ScoreType ORB_ScoreType;
-
-CV_PY_FROM_ENUM(AKAZE::DescriptorType);
-CV_PY_TO_ENUM(AKAZE::DescriptorType);
-CV_PY_FROM_ENUM(AgastFeatureDetector::DetectorType);
-CV_PY_TO_ENUM(AgastFeatureDetector::DetectorType);
-CV_PY_FROM_ENUM(DrawMatchesFlags);
-CV_PY_TO_ENUM(DrawMatchesFlags);
-CV_PY_FROM_ENUM(FastFeatureDetector::DetectorType);
-CV_PY_TO_ENUM(FastFeatureDetector::DetectorType);
-CV_PY_FROM_ENUM(DescriptorMatcher::MatcherType);
-CV_PY_TO_ENUM(DescriptorMatcher::MatcherType);
-CV_PY_FROM_ENUM(KAZE::DiffusivityType);
-CV_PY_TO_ENUM(KAZE::DiffusivityType);
-CV_PY_FROM_ENUM(ORB::ScoreType);
-CV_PY_TO_ENUM(ORB::ScoreType);
 #endif
\ No newline at end of file
diff --git a/modules/objdetect/misc/python/pyopencv_objdetect.hpp b/modules/objdetect/misc/python/pyopencv_objdetect.hpp
index 3d09ae16bf..def93f53e6 100644
--- a/modules/objdetect/misc/python/pyopencv_objdetect.hpp
+++ b/modules/objdetect/misc/python/pyopencv_objdetect.hpp
@@ -5,9 +5,4 @@
 typedef HOGDescriptor::HistogramNormType HOGDescriptor_HistogramNormType;
 typedef HOGDescriptor::DescriptorStorageFormat HOGDescriptor_DescriptorStorageFormat;
 
-CV_PY_FROM_ENUM(HOGDescriptor::HistogramNormType);
-CV_PY_TO_ENUM(HOGDescriptor::HistogramNormType);
-CV_PY_FROM_ENUM(HOGDescriptor::DescriptorStorageFormat);
-CV_PY_TO_ENUM(HOGDescriptor::DescriptorStorageFormat);
-
 #endif
diff --git a/modules/python/src2/cv2.cpp b/modules/python/src2/cv2.cpp
index 5ae963a94f..1631daaff0 100644
--- a/modules/python/src2/cv2.cpp
+++ b/modules/python/src2/cv2.cpp
@@ -1669,6 +1669,7 @@ static int convert_to_char(PyObject *o, char *dst, const char *name = "no_name")
 #  pragma GCC diagnostic ignored "-Wmissing-field-initializers"
 #endif
 
+#include "pyopencv_generated_enums.h"
 #include "pyopencv_custom_headers.h"
 #include "pyopencv_generated_types.h"
 #include "pyopencv_generated_funcs.h"
diff --git a/modules/python/src2/gen2.py b/modules/python/src2/gen2.py
index 9830d9637c..7dd69fce83 100755
--- a/modules/python/src2/gen2.py
+++ b/modules/python/src2/gen2.py
@@ -688,7 +688,7 @@ class FuncInfo(object):
                         defval0 = "0"
                         tp1 = tp.replace("*", "_ptr")
                 tp_candidates = [a.tp, normalize_class_name(self.namespace + "." + a.tp)]
-                if any(tp in codegen.enumTypes for tp in tp_candidates):
+                if any(tp in codegen.enums.keys() for tp in tp_candidates):
                     defval0 = "static_cast<%s>(%d)" % (a.tp, 0)
 
                 amapping = simple_argtype_mapping.get(tp, (tp, "O", defval0))
@@ -863,8 +863,9 @@ class PythonWrapperGenerator(object):
         self.classes = {}
         self.namespaces = {}
         self.consts = {}
-        self.enumTypes = []
+        self.enums = {}
         self.code_include = StringIO()
+        self.code_enums = StringIO()
         self.code_types = StringIO()
         self.code_funcs = StringIO()
         self.code_type_reg = StringIO()
@@ -922,11 +923,11 @@ class PythonWrapperGenerator(object):
         #print(cname + ' => ' + str(py_name) + ' (value=' + value + ')')
 
     def add_enum(self, name, decl):
-        enumType = normalize_class_name(name)
-        if enumType.endswith("<unnamed>"):
-            enumType = None
+        wname = normalize_class_name(name)
+        if wname.endswith("<unnamed>"):
+            wname = None
         else:
-            self.enumTypes.append(enumType)
+            self.enums[wname] = name
         const_decls = decl[3]
 
         for decl in const_decls:
@@ -1017,6 +1018,21 @@ class PythonWrapperGenerator(object):
                 self.code_ns_reg.write('  init_submodule(root, MODULESTR"%s", methods_%s, consts_%s);\n' % (ns_name[2:], wname, wname))
         self.code_ns_reg.write('};\n')
 
+    def gen_enum_reg(self, enum_name):
+        name_seg = enum_name.split(".")
+        is_enum_class = False
+        if len(name_seg) >= 2 and name_seg[-1] == name_seg[-2]:
+            enum_name = ".".join(name_seg[:-1])
+            is_enum_class = True
+
+        wname = normalize_class_name(enum_name)
+        cname = enum_name.replace(".", "::")
+
+        code = ""
+        if re.sub(r"^cv\.", "", enum_name) != wname:
+            code += "typedef {0} {1};\n".format(cname, wname)
+        code += "CV_PY_FROM_ENUM({0});\nCV_PY_TO_ENUM({0});\n\n".format(wname)
+        self.code_enums.write(code)
 
     def save(self, path, name, buf):
         with open(path + "/" + name, "wt") as f:
@@ -1131,7 +1147,13 @@ class PythonWrapperGenerator(object):
             self.gen_namespace(ns_name)
         self.gen_namespaces_reg()
 
-        # step 4: generate the code for constants
+        # step 4: generate the code for enum types
+        enumlist = list(self.enums.values())
+        enumlist.sort()
+        for name in enumlist:
+            self.gen_enum_reg(name)
+
+        # step 5: generate the code for constants
         constlist = list(self.consts.items())
         constlist.sort()
         for name, constinfo in constlist:
@@ -1140,6 +1162,7 @@ class PythonWrapperGenerator(object):
         # That's it. Now save all the files
         self.save(output_path, "pyopencv_generated_include.h", self.code_include)
         self.save(output_path, "pyopencv_generated_funcs.h", self.code_funcs)
+        self.save(output_path, "pyopencv_generated_enums.h", self.code_enums)
         self.save(output_path, "pyopencv_generated_types.h", self.code_types)
         self.save(output_path, "pyopencv_generated_type_reg.h", self.code_type_reg)
         self.save(output_path, "pyopencv_generated_ns_reg.h", self.code_ns_reg)
diff --git a/modules/stitching/misc/python/pyopencv_stitching.hpp b/modules/stitching/misc/python/pyopencv_stitching.hpp
index e5d0cd2481..9c438356b8 100644
--- a/modules/stitching/misc/python/pyopencv_stitching.hpp
+++ b/modules/stitching/misc/python/pyopencv_stitching.hpp
@@ -1,9 +1,4 @@
 #ifdef HAVE_OPENCV_STITCHING
 typedef Stitcher::Status Status;
 
-template<>
-PyObject* pyopencv_from(const Status& value)
-{
-    return PyInt_FromLong(value);
-}
 #endif
\ No newline at end of file
diff --git a/modules/videoio/misc/python/pyopencv_videoio.hpp b/modules/videoio/misc/python/pyopencv_videoio.hpp
index 453a57a126..8ea62ebd73 100644
--- a/modules/videoio/misc/python/pyopencv_videoio.hpp
+++ b/modules/videoio/misc/python/pyopencv_videoio.hpp
@@ -1,33 +1,6 @@
 #ifdef HAVE_OPENCV_VIDEOIO
 typedef std::vector<VideoCaptureAPIs> vector_VideoCaptureAPIs;
 
-template<>
-bool pyopencv_to(PyObject *o, cv::VideoCaptureAPIs &v, const char *name)
-{
-    (void)name;
-    v = CAP_ANY;
-    if (!o || o == Py_None)
-        return false;
-    else if (PyLong_Check(o))
-    {
-        v = VideoCaptureAPIs((int64)PyLong_AsLongLong(o));
-        return true;
-    }
-    else if (PyInt_Check(o))
-    {
-        v = VideoCaptureAPIs((int64)PyInt_AS_LONG(o));
-        return true;
-    }
-    else
-        return false;
-}
-
-template<>
-PyObject* pyopencv_from(const cv::VideoCaptureAPIs &v)
-{
-    return pyopencv_from((int)(v));
-}
-
 template<> struct pyopencvVecConverter<cv::VideoCaptureAPIs>
 {
     static bool to(PyObject* obj, std::vector<cv::VideoCaptureAPIs>& value, const ArgInfo info)