diff --git a/src/storage/dft/DFT.cpp b/src/storage/dft/DFT.cpp
index a23a70f71..0dedd9fb3 100644
--- a/src/storage/dft/DFT.cpp
+++ b/src/storage/dft/DFT.cpp
@@ -3,6 +3,9 @@
 #include "DFT.h"
 #include "src/exceptions/NotSupportedException.h"
 
+#include "DFTIsomorphism.h"
+#include "utility/iota_n.h"
+
 namespace storm {
     namespace storage {
 
@@ -168,6 +171,43 @@ namespace storm {
             return ISD;
         }
 
+        template<typename ValueType>
+        DFTColouring<ValueType> DFT<ValueType>::colourDFT() const {
+            return DFTColouring<ValueType>(*this);
+        }
+
+        template<typename ValueType>
+        std::vector<std::vector<size_t>> DFT<ValueType>::findSymmetries(DFTColouring<ValueType> const& colouring) const {
+            std::vector<size_t> vec;
+            vec.reserve(nrElements());
+            storm::utility::iota_n(std::back_inserter(vec), 14, 0);
+            BijectionCandidates<ValueType> completeCategories = colouring.colourSubdft(vec);
+            std::vector<std::vector<size_t>> res;
+            for(auto const& colourClass : completeCategories.gateCandidates) {
+                if(colourClass.second.size() > 1) {
+                    for(auto it1 = colourClass.second.cbegin(); it1 != colourClass.second.cend(); ++it1) {
+                        std::vector<size_t> sortedParent1Ids = getGate(*it1)->parentIds();
+                        std::sort(sortedParent1Ids.begin(), sortedParent1Ids.end());
+                        auto it2 = it1;
+                        for(++it2; it2 != colourClass.second.cend(); ++it2) {
+                            std::vector<size_t> sortedParent2Ids = getGate(*it2)->parentIds();
+                            std::sort(sortedParent2Ids.begin(), sortedParent2Ids.end());
+                            if(sortedParent1Ids == sortedParent2Ids) {
+                                std::cout << "Considering ids " << *it1 << ", " << *it2 << " for isomorphism." << std::endl;
+                                std::vector<size_t> isubdft1 = getGate(*it1)->independentSubDft();
+                                std::vector<size_t> isubdft2 = getGate(*it2)->independentSubDft();
+                                if(!isubdft1.empty() && !isubdft2.empty() && isubdft1.size() == isubdft2.size()) {
+                                    std::cout << "Checking subdfts from " << *it1 << ", " << *it2 << " for isomorphism." << std::endl;
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+            return res;
+        }
+
+
         // Explicitly instantiate the class.
         template class DFT<double>;
 
diff --git a/src/storage/dft/DFT.h b/src/storage/dft/DFT.h
index ecea467e4..f2036e7d7 100644
--- a/src/storage/dft/DFT.h
+++ b/src/storage/dft/DFT.h
@@ -29,6 +29,11 @@ namespace storm {
             }
         };
 
+
+        // Forward declarations
+        template<typename T> class DFTColouring;
+
+
         /**
          * Represents a Dynamic Fault Tree
          */
@@ -222,6 +227,11 @@ namespace storm {
             std::string getStateString(DFTStatePointer const& state) const;
 
             std::vector<size_t> getIndependentSubDftRoots(size_t index) const;
+
+            DFTColouring<ValueType> colourDFT() const;
+
+            std::vector<std::vector<size_t>> findSymmetries(DFTColouring<ValueType> const& colouring) const;
+
         private:
             bool elementIndicesCorrect() const {
                 for(size_t i = 0; i < mElements.size(); ++i) {
diff --git a/src/storage/dft/DFTIsomorphism.h b/src/storage/dft/DFTIsomorphism.h
index e9a58d559..6258b05bc 100644
--- a/src/storage/dft/DFTIsomorphism.h
+++ b/src/storage/dft/DFTIsomorphism.h
@@ -1,9 +1,12 @@
 #pragma once
 
+#include <cassert>
 #include <vector>
 #include <unordered_map>
+#include <utility>
 #include "DFTElementType.h"
 #include "DFTElements.h"
+#include "DFT.h"
 
 namespace storm {
 namespace storage {
@@ -34,14 +37,102 @@ namespace storage {
 
     };
 
+
+    template<typename ValueType>
+    struct BEColourClass {
+        BEColourClass() = default;
+        BEColourClass(ValueType a, ValueType p, size_t h) : aRate(a), pRate(p), hash(h) {}
+
+        ValueType aRate;
+        ValueType pRate;
+        size_t    hash;
+    };
+
+    template<typename ValueType>
+    bool operator==(BEColourClass<ValueType> const& lhs, BEColourClass<ValueType> const& rhs) {
+        return lhs.hash == rhs.hash && lhs.aRate == rhs.aRate && lhs.pRate == rhs.pRate;
+    }
+
+
+
+
     /**
      *
      */
     template<typename ValueType>
-    class BijectionCandidates {
-        std::unordered_map<size_t, std::vector<size_t>> groupCandidates;
-        std::unordered_map<std::pair<ValueType, ValueType>, std::vector<size_t>> beCandidates;
+    struct BijectionCandidates {
+        std::unordered_map<size_t, std::vector<size_t>> gateCandidates;
+        std::unordered_map<BEColourClass<ValueType>, std::vector<size_t>> beCandidates;
+        std::unordered_map<std::pair<ValueType, ValueType>, std::vector<size_t>> pdepCandidates;
+    };
+
+    template<typename ValueType>
+    class DFTColouring {
+        DFT<ValueType> const& dft;
+        std::unordered_map<size_t, size_t> gateColour;
+        std::unordered_map<size_t, BEColourClass<ValueType>> beColour;
+        std::unordered_map<size_t, std::pair<ValueType, ValueType>> depColour;
+        GateGroupToHash gateColourizer;
+
+    public:
+        DFTColouring(DFT<ValueType> const& ft) : dft(ft) {
+            for(size_t id = 0; id < dft.nrElements(); ++id ) {
+                if(dft.isBasicElement(id)) {
+                    colourize(dft.getBasicElement(id));
+                } else if(dft.isGate(id)) {
+                    colourize(dft.getGate(id));
+                } else {
+                    assert(dft.isDependency(id));
+                    colourize(dft.getDependency(id));
+                }
+            }
+        }
 
+
+        BijectionCandidates<ValueType> colourSubdft(std::vector<size_t> const& subDftIndices) const {
+            BijectionCandidates<ValueType> res;
+            for (size_t index : subDftIndices) {
+                if(dft.isBasicElement(index)) {
+                    auto it = res.beCandidates.find(beColour.at(index));
+                    if(it != res.beCandidates.end()) {
+                        it->second.push_back(index);
+                    } else {
+                        res.beCandidates[beColour.at(index)] = std::vector<size_t>({index});
+                    }
+                } else if(dft.isGate(index)) {
+                    auto it = res.gateCandidates.find(gateColour.at(index));
+                    if(it != res.gateCandidates.end()) {
+                        it->second.push_back(index);
+                    } else {
+                        res.gateCandidates[gateColour.at(index)] = std::vector<size_t>({index});
+                    }
+                } else {
+                    assert(dft.isDependency(index));
+                    auto it = res.pdepCandidates.find(depColour.at(index));
+                    if(it != res.pdepCandidates.end()) {
+                        it->second.push_back(index);
+                    } else {
+                        res.pdepCandidates[depColour.at(index)] = std::vector<size_t>({index});
+                    }
+                }
+
+            }
+            return res;
+        }
+
+
+    protected:
+        void colourize(std::shared_ptr<const DFTBE<ValueType>> const& be) {
+             beColour[be->id()] = BEColourClass<ValueType>(be->activeFailureRate(), be->passiveFailureRate(), be->nrParents());
+        }
+
+        void colourize(std::shared_ptr<const DFTGate<ValueType>> const& gate) {
+             gateColour[gate->id()] = gateColourizer(gate->type(), gate->nrChildren(), gate->nrParents(), 0, gate->rank());
+        }
+        
+        void colourize(std::shared_ptr<const DFTDependency<ValueType>> const& dep) {
+            depColour[dep->id()] = std::pair<ValueType, ValueType>(dep->probability(), dep->dependentEvent()->activeFailureRate());
+        }
     };
 
 
@@ -107,36 +198,61 @@ namespace storage {
         }
 
     protected:
-
+        /**
+         * Construct the initial bijection.
+         */
         void constructInitialBijection() {
             assert(candidatesCompatible);
             // We first construct the currentPermutations, which helps to determine the current state of the check.
-            for(auto const& colour : bright.beCandidates) {
-                if(colour.second.size()>1) {
-                    currentPermutations.beCandidates.insert(colour);
+            initializePermutationsAndTreatTrivialGroups(bleft.beCandidates, bright.beCandidates, currentPermutations.beCandidates);
+            initializePermutationsAndTreatTrivialGroups(bleft.gateCandidates, bright.gateCandidates, currentPermutations.gateCandidates);
+            initializePermutationsAndTreatTrivialGroups(bleft.pdepCandidates, bright.pdepCandidates, currentPermutations.pdepCandidates);
+        }
+
+        /**
+         * Construct the next bijection
+         * @return true if a next bijection exists.
+         */
+        bool findNextBijection() {
+            bool foundNext = false;
+            if(!currentPermutations.beCandidates.empty()) {
+                auto it = currentPermutations.beCandidates.begin();
+                while(!foundNext && it == currentPermutations.beCandidates.end()) {
+                    foundNext = std::next_permutation(it->second.begin(), it->second.end());
+                    ++it;
                 }
             }
-
-            for(auto const& colour : bright.groupCandidates) {
-                if(colour.second.size()>1) {
-                    currentPermutations.groupCandidates.insert(colour);
+            if(!foundNext && !currentPermutations.gateCandidates.empty()) {
+                auto it = currentPermutations.gateCandidates.begin();
+                while(!foundNext && it == currentPermutations.beCandidates.end()) {
+                    foundNext = std::next_permutation(it->second.begin(), it->second.end());
+                    ++it;
                 }
             }
 
-            // Constructing the initial homomorphism based on the right hand side instead of the current permutations allows us
-            // to treat trivial and non-trivial classes in one go.
-            for(auto const& colour : bleft.beCandidates) {
-                zipVectorsIntoMap(colour.second, bright.beCandidates.find(colour.first)->second, bijection);
+            if(!foundNext && !currentPermutations.pdepCandidates.empty()) {
+                auto it = currentPermutations.pdepCandidates.begin();
+                while(!foundNext && it == currentPermutations.pdepCandidates.end()) {
+                    foundNext = std::next_permutation(it->second.begin(), it->second.end());
+                    ++it;
+                }
             }
 
-            for(auto const& colour : bleft.groupCandidates) {
-                zipVectorsIntoMap(colour.second, bright.groupCandidates.find(colour.first)->second, bijection);
-            }
+            if(foundNext) {
+                for(auto const& colour : bleft.beCandidates) {
+                    zipVectorsIntoMap(colour.second, currentPermutations.beCandidates.find(colour.first)->second, bijection);
+                }
 
-        }
+                for(auto const& colour : bleft.gateCandidates) {
+                    zipVectorsIntoMap(colour.second, currentPermutations.gateCandidates.find(colour.first)->second, bijection);
+                }
 
-        bool findNextBijection() {
-            return false;
+                for(auto const& colour : bleft.pdepCandidates) {
+                    zipVectorsIntoMap(colour.second, currentPermutations.pdepCandidates.find(colour.first)->second, bijection);
+                }
+            }
+
+            return foundNext;
         }
 
 
@@ -152,21 +268,21 @@ namespace storage {
          * Returns true if the colours are compatible.
          */
         bool checkCompatibility() {
-            if(bleft.groupCandidates.size() != bright.groupCandidates.size()) {
+            if(bleft.gateCandidates.size() != bright.gateCandidates.size()) {
                 candidatesCompatible = false;
             }
             else if(bleft.beCandidates.size() != bright.beCandidates.size()) {
                 candidatesCompatible = false;
             }
             else {
-                for (auto const &gc : bleft.groupCandidates) {
-                    if (bright.groupCandidates.count(gc.first) == 0) {
+                for (auto const &gc : bleft.gateCandidates) {
+                    if (bright.gateCandidates.count(gc.first) == 0) {
                         candidatesCompatible = false;
                         break;
                     }
                 }
                 if(candidatesCompatible) {
-                    for(auto const& bc : bleft.groupCandidates) {
+                    for(auto const& bc : bleft.gateCandidates) {
                         if(bright.beCandidates.count(bc.first) == 0) {
                             candidatesCompatible = false;
                             break;
@@ -176,6 +292,26 @@ namespace storage {
             }
         }
 
+        /**
+         *
+         */
+        template<typename ColourType>
+        void initializePermutationsAndTreatTrivialGroups(std::unordered_map<ColourType, std::vector<size_t>> const& left,
+                                                         std::unordered_map<ColourType, std::vector<size_t>> const& right,
+                                                         std::unordered_map<ColourType, std::vector<size_t>>& permutations) {
+            for(auto const& colour : right) {
+                if(colour.second.size()>1) {
+                    auto it = permutations.insert(colour);
+                    std::sort(it->second.begin(), it->second.end());
+                    zipVectorsIntoMap(colour.second, permutations.find(colour.first)->second, bijection);
+                } else {
+                    assert(colour.second.size() == 1);
+                    assert(bijection.count(left[colour.first].front()) == 0);
+                    bijection[left[colour.first].front()] = colour.second.front();
+                }
+            }
+        }
+
         /**
          * Local helper function for the creation of bijections, should be hidden from api.
          */
@@ -184,7 +320,6 @@ namespace storage {
             assert(a.size() == b.size());
             auto it = b.cbegin();
             for(size_t lIndex : a) {
-                assert(map.count(lIndex) == 0);
                 map[lIndex] = *it;
                 ++it;
             }
@@ -199,3 +334,21 @@ namespace storage {
 
 } // namespace storm::dft
 } // namespace storm
+
+namespace std {
+    template<typename ValueType>
+    struct hash<storm::storage::BEColourClass<ValueType>> {
+        size_t operator()(storm::storage::BEColourClass<ValueType> const& bcc) const {
+            std::hash<ValueType> hasher;
+            return (hasher(bcc.aRate) ^ hasher(bcc.pRate) << 8) | bcc.hash;
+        }
+    };
+
+    template<typename ValueType>
+    struct hash<std::pair<ValueType, ValueType>> {
+        size_t operator()(std::pair<ValueType, ValueType> const& p) const {
+            std::hash<ValueType> hasher;
+            return hasher(p.first) ^ hasher(p.second);
+        }
+    };
+}
\ No newline at end of file
diff --git a/src/utility/iota_n.h b/src/utility/iota_n.h
new file mode 100644
index 000000000..a7e4ba829
--- /dev/null
+++ b/src/utility/iota_n.h
@@ -0,0 +1,13 @@
+#pragma once
+
+namespace storm {
+    namespace utility {
+        template<class OutputIterator, class Size, class Assignable>
+        void iota_n(OutputIterator first, Size n, Assignable value)
+        {
+            std::generate_n(first, n, [&value]() {
+                return value++;
+            });
+        }
+    }
+}