protected function _getTable($parts, $fallback = true)
    {
        if (!is_array($parts) || count($parts) === 1) {
            return $this->_tables[$this->_rootName];
        }

        $normalized = array_slice(array_filter($parts, function ($part) {
            return !is_numeric($part);
        }), 0, -1);

        $path = implode('.', $normalized);
        if (isset($this->_tables[$path])) {
            return $this->_tables[$path];
        }

        if (current($normalized) === $this->_rootName) {
            $normalized = array_slice($normalized, 1);
        }

        $table = $this->_tables[$this->_rootName];
        $assoc = null;
        foreach ($normalized as $part) {
            if ($part === '_joinData') {
                if ($assoc) {
                    $table = $assoc->junction();
                    $assoc = null;
                    continue;
                }
            } else {
                $assoc = $table->associations()->getByProperty($part);
            }

            if (!$assoc && $fallback) {
                break;
            }
            if (!$assoc && !$fallback) {
                return false;
            }

            $table = $assoc->getTarget();
        }

        return $this->_tables[$path] = $table;
    }