diff --git a/.ci/generate_bear_metadata.py b/.ci/generate_bear_metadata.py
index d6389145bb..bcc8e5567b 100755
--- a/.ci/generate_bear_metadata.py
+++ b/.ci/generate_bear_metadata.py
@@ -322,11 +322,6 @@ def get_bear_tags(bear, metadata):
             tags.remove('java')
         tags.add('opam')
 
-    elif bear.name == 'CPDBear':
-        # Has no requirements defined yet
-        tags.remove('noreqs')
-        tags.add('java')
-
     elif bear.name == 'LanguageToolBear':
         # Has no requirements defined yet
         tags.add('java')
@@ -337,8 +332,7 @@ def get_bear_tags(bear, metadata):
         tags.add('pmd')
 
     elif bear.name == 'CPDBear':
-        # Has no executable defined
-        tags.add('cpd')
+        tags.add('java')
 
     elif bear.name == 'VHDLLintBear':
         # Has no executable defined
diff --git a/bear-metadata.yaml b/bear-metadata.yaml
index 6cb7f2a783..d0bf16f0b3 100644
--- a/bear-metadata.yaml
+++ b/bear-metadata.yaml
@@ -154,6 +154,9 @@ bear_metadata:
     subdir: general
     filename: CPDBear.py
     requirements:
+      exe:
+        cpd:
+        run.sh:
     languages:
       - C#
       - CPP
@@ -174,8 +177,11 @@ bear_metadata:
       - Scala
       - Swift
     tags:
+      - cpd
+      - exe
       - general
       - java
+      - run.sh
   CPPCheckBear:
     name: CPPCheckBear
     subdir: c_languages
diff --git a/bears/general/CPDBear.py b/bears/general/CPDBear.py
index 4914194646..c50c51833a 100644
--- a/bears/general/CPDBear.py
+++ b/bears/general/CPDBear.py
@@ -1,6 +1,11 @@
 from shutil import which
 from xml.etree import ElementTree
 
+from dependency_management.requirements.AnyOneOfRequirements import (
+    AnyOneOfRequirements)
+from dependency_management.requirements.ExecutableRequirement import (
+    ExecutableRequirement)
+
 from coalib.bears.GlobalBear import GlobalBear
 from coalib.misc.Shell import run_shell_command
 from coalib.results.Result import Result
@@ -30,21 +35,18 @@ class CPDBear(GlobalBear):
                      'Swift': 'swift'}
 
     LANGUAGES = set(language_dict.keys())
+    REQUIREMENTS = {
+        AnyOneOfRequirements(
+            [ExecutableRequirement('cpd'),
+             ExecutableRequirement('run.sh'),
+             ]
+        ),
+    }
     AUTHORS = {'The coala developers'}
     AUTHORS_EMAILS = {'coala-devel@googlegroups.com'}
     LICENSE = 'AGPL-3.0'
     CAN_DETECT = {'Duplication'}
 
-    @classmethod
-    def check_prerequisites(cls):
-        if which('bash') is None:
-            return 'bash is not installed.'
-        if which('pmd') is None and which('run.sh') is None:
-            return ('PMD is missing. Make sure to install it from '
-                    '<https://pmd.github.io/>.')
-        else:
-            return True
-
     def run(self, language: language,
             minimum_tokens: int = 20,
             ignore_annotations: bool = False,
@@ -93,8 +95,11 @@ def run(self, language: language,
             '--skip-duplicate-files': skip_duplicate_files}
 
         files = ','.join(self.file_dict.keys())
-        executable = which('pmd') or which('run.sh')
-        arguments = ('bash', executable, 'cpd', '--skip-lexical-errors',
+        executable = which('cpd') or which('run.sh')
+        executable = tuple([executable] if not executable.endswith('run.sh')
+                           else [executable, 'cpd'])
+
+        arguments = ('--skip-lexical-errors',
                      '--minimum-tokens', str(minimum_tokens),
                      '--language', cpd_language,
                      '--files', files,
@@ -104,6 +109,7 @@ def run(self, language: language,
                            for option, enable in options.items()
                            if enable is True)
 
+        arguments = executable + arguments
         stdout_output, _ = run_shell_command(arguments)
 
         if stdout_output:
diff --git a/tests/general/CPDBearTest.py b/tests/general/CPDBearTest.py
index aa33e08b68..3984febdd9 100644
--- a/tests/general/CPDBearTest.py
+++ b/tests/general/CPDBearTest.py
@@ -1,6 +1,5 @@
 import os
 import unittest
-from unittest import mock
 
 from queue import Queue
 import logging
@@ -68,14 +67,3 @@ def test_unsupported_language(self):
             self.uut.message_queue.queue[0].log_level, logging.ERROR)
         self.assertIn('Hypertext Markup Language',
                       self.uut.message_queue.queue[0].message)
-
-    def test_check_prerequisites(self):
-        with mock.patch('bears.general.CPDBear.which') as mock_which:
-            mock_which.side_effect = [None, None, None]
-            self.assertEqual(CPDBear.check_prerequisites(),
-                             'bash is not installed.')
-
-            mock_which.side_effect = ['path/to/bash', None, None]
-            self.assertEqual(CPDBear.check_prerequisites(),
-                             'PMD is missing. Make sure to install it '
-                             'from <https://pmd.github.io/>.')