private function validateGenericNode($value, $object, $cacheKey, MetadataInterface $metadata = null, $propertyPath, array $groups, $cascadedGroups, $traversalStrategy, ExecutionContextInterface $context)
    {
        $context->setNode($value, $object, $metadata, $propertyPath);

        foreach ($groups as $key => $group) {
            if ($group instanceof GroupSequence) {
                $this->stepThroughGroupSequence(
                     $value,
                     $object,
                     $cacheKey,
                     $metadata,
                     $propertyPath,
                     $traversalStrategy,
                     $group,
                     null,
                     $context
                );

                // Skip the group sequence when cascading, as the cascading
                // logic is already done in stepThroughGroupSequence()
                unset($groups[$key]);

                continue;
            }

            $this->validateInGroup($value, $cacheKey, $metadata, $group, $context);
        }

        if (0 === \count($groups)) {
            return;
        }

        if (null === $value) {
            return;
        }

        $cascadingStrategy = $metadata->getCascadingStrategy();

        // Quit unless we cascade
        if (!($cascadingStrategy & CascadingStrategy::CASCADE)) {
            return;
        }

        // If no specific traversal strategy was requested when this method
        // was called, use the traversal strategy of the node's metadata
        if ($traversalStrategy & TraversalStrategy::IMPLICIT) {
            $traversalStrategy = $metadata->getTraversalStrategy();
        }

        // The $cascadedGroups property is set, if the "Default" group is
        // overridden by a group sequence
        // See validateClassNode()
        $cascadedGroups = null !== $cascadedGroups && \count($cascadedGroups) > 0 ? $cascadedGroups : $groups;

        if (\is_array($value)) {
            // Arrays are always traversed, independent of the specified
            // traversal strategy
            $this->validateEachObjectIn(
                $value,
                $propertyPath,
                $cascadedGroups,
                $context
            );

            return;
        }

        // If the value is a scalar, pass it anyway, because we want
        // a NoSuchMetadataException to be thrown in that case
        $this->validateObject(
            $value,
            $propertyPath,
            $cascadedGroups,
            $traversalStrategy,
            $context
        );

        // Currently, the traversal strategy can only be TRAVERSE for a
        // generic node if the cascading strategy is CASCADE. Thus, traversable
        // objects will always be handled within validateObject() and there's
        // nothing more to do here.

        // see GenericMetadata::addConstraint()
    }